[
  {
    "path": ".github/CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment include:\n\n* Using welcoming and inclusive language\n* Being respectful of differing viewpoints and experiences\n* Gracefully accepting constructive criticism\n* Focusing on what is best for the community\n* Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery and unwelcome sexual attention or advances\n* Trolling, insulting/derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or electronic address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]\n\n[homepage]: http://contributor-covenant.org\n[version]: http://contributor-covenant.org/version/1/4/\n"
  },
  {
    "path": ".github/CONTRIBUTING.md",
    "content": "# Contributing\n\nFirst off, thanks for taking the time to contribute!\n\nThe following is a set of guidelines for contributing to this project. These are mostly guidelines, not rules. Use your best judgment, and feel free to propose changes to this document in a pull request.\n\n#### Table Of Contents\n\n* [Code of Conduct](#code-of-conduct)\n* [Project governance](#project-governance)\n  * [Rules](#rules)\n  * [Releases](#releases)\n  * [Changes to this arrangement](#changes-to-this-arrangement)\n* [Pull Requests](#pull-requests)\n* [Styleguides](#styleguides)\n  * [Git Commit Messages](#git-commit-messages)\n  * [JavaScript Styleguide](#javascript-styleguide)\n  * [Tests Styleguide](#tests-styleguide)\n* [Developer's certificate of origin](#developers-certificate-of-origin)\n\n## Code of Conduct\n\nThis project and everyone participating in it is governed by the [Code of Conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code.\n\n## Project Governance\n\nIndividuals making significant and valuable contributions are given commit-access to the project to contribute as they see fit.\n\n### Rules\n\nThere are a few basic ground-rules for contributors:\n\n1. **No `--force` pushes** or modifying the Git history in any way.\n2. **All modifications** should be subject to a **pull request** to solicit feedback from other contributors. The base branch of the pull request should correspond with the assigned \"release milestone\" of the related issue. When an issue is created, it will be prioritized and a \"release milestone\" will be assigned to it, at the criteria of contributors. A branch will be created from master for that release milestone, and all related issues should be merged into it, until is ready to declare a formal release.\n3. **All changes** to this project will be documented in the GHANGELOG.md file.\n\n### Releases\n\nDeclaring formal releases remains the prerogative of the project maintainer. \n\n### Changes to this arrangement\n\nThis document may also be subject to pull-requests or changes by contributors where you believe you have something valuable to add or change.\n\n## Pull Requests\n\n* Fill in [the required template](PULL_REQUEST_TEMPLATE.md).\n* Do not include issue numbers in the PR title.\n* Follow the [JavaScript styleguide](#javascript-styleguide).\n* Follow the [Tests styleguide](#tests-styleguide).\n* All enhancements and bug fixes must be accompanied with all needed new related regression test.\n* Coverage of unit tests must remain 100%.\n* Run tests often. Tests are ran automatically with Travis when you push, but you still need to run them locally before pushing.\n* Document new features, or update documentation if changes affect to it.\n* End all files with a newline.\n* Place requires in the following order:\n    * Built in Node Modules (such as `path`)\n    * NPM Modules (such as `lodash`)\n    * Local Modules (using relative paths)\n\n## Styleguides\n\n### Git Commit Messages\n\n* Use the present tense (\"Add feature\" not \"Added feature\")\n* Use the imperative mood (\"Move cursor to...\" not \"Moves cursor to...\")\n* Limit the first line to 72 characters or less\n* Reference issues and pull requests liberally after the first line\n\n### JavaScript Styleguide\n\nAll JavaScript must adhere to the style defined in the `.eslintrc.js` file.\n\n### Tests Styleguide\n\n- Fail tests first. How do you know if it is actually testing anything if the assert never failed?\n- Treat `describe` as a noun or situation (Situations usually start with \"when\").\n- Treat `it` as a statement about state or how an operation changes state. Usually, all `it` should start with \"should\".\n- Prefer fewer asserts per `it`.\n- Prefer one file for all specs of a javascript file, but, if it grows too much, split it into many files adding a sufix describing the behavior being tested in it (`file.behavior.js`)\n\n#### Example\n\n```js\ndescribe(\"a dog\", () => {\n  describe(\"when is happy\", () => {\n    it(\"should wags its tail\", () => {\n      expect(dog.tail.moving).to.be.true();\n    });\n  });\n});\n```\n\n## Developer's Certificate of Origin\n\nBy making a contribution to this project, I certify that:\n\n- (a) The contribution was created in whole or in part by me and I have the right to\n  submit it under the open source license indicated in the file; or\n\n- (b) The contribution is based upon previous work that, to the best of my knowledge, is\n  covered under an appropriate open source license and I have the right under that license\n  to submit that work with modifications, whether created in whole or in part by me, under\n  the same open source license (unless I am permitted to submit under a different\n  license), as indicated in the file; or\n\n- (c) The contribution was provided directly to me by some other person who certified\n  (a), (b) or (c) and I have not modified it.\n\n- (d) I understand and agree that this project and the contribution are public and that a\n  record of the contribution (including all personal information I submit with it,\n  including my sign-off) is maintained indefinitely and may be redistributed consistent\n  with this project or the open source license(s) involved.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\n\n---\n\n**Describe the bug**\nA clear and concise description of what the bug is.\n\n**To Reproduce**\nSteps to reproduce the behavior\n\n**Expected behavior**\nA clear and concise description of what you expected to happen.\n\n**Logs**\nIf applicable, add logs to help explain your problem.\n\n** Operating system, Node.js an npm versions, or browser version (please complete the following information):**\n - OS: [e.g. Ubuntu 18.04]\n - Node.js: [e.g. 8.11.1]\n - npm: [e.g. 5.6.0]\n - Browser: [e.g. Chrome 73.0.3683]\n\n**Additional context**\nAdd any other context about the problem here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\n\n---\n\n**Is your feature request related to a problem? Please describe.**\nA clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n\n**Describe the solution you'd like**\nA clear and concise description of what you want to happen.\n\n**Describe alternatives you've considered**\nA clear and concise description of any alternative solutions or features you've considered.\n\n**Additional context**\nAdd any other context or examples about the feature request here.\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "**IMPORTANT: Please do not create a Pull Request without creating an issue first.**\n\n*Any change needs to be discussed before proceeding. Failure to do so may result in the rejection of the pull request.*\n\nPlease provide enough information so that others can review your pull request:\n\nExplain the **details** for making this change. What existing problem does the pull request solve?\n\n**Closing issues**\n\nPut `closes #XXXX` in your comment to auto-close the issue that your PR fixes.\n"
  },
  {
    "path": ".github/workflows/build.yml",
    "content": "name: build\non:\n  push:\n    branches:\n      - master\n      - release\n  pull_request:\nconcurrency:  \n  group: ${{ github.workflow }}-${{ github.ref }}\n  cancel-in-progress: true\njobs:\n  test:\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        node: [\"20.13.1\", \"22.2.0\", \"24.4.1\"]\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v4\n      - name: Extract branch name\n        shell: bash\n        run: echo \"branch=$(echo ${GITHUB_REF##*/})\" >> $GITHUB_OUTPUT\n        id: extract-branch\n      - name: Install pnpm\n        uses: pnpm/action-setup@v4\n      - name: Install Node.js\n        uses: actions/setup-node@v4\n        with:\n          node-version: ${{ matrix.node }}\n      - name: Install dependencies\n        run: pnpm install\n      - name: Check spelling\n        if: ${{ matrix.node == '24.4.1' }}\n        run: pnpm run cspell\n      - name: Lint\n        if: ${{ matrix.node == '24.4.1' }}\n        run: pnpm run lint\n      - name: Check types\n        if: ${{ matrix.node == '24.4.1' }}\n        run: pnpm run tsc\n      - name: Test unit\n        run: pnpm run test:unit\n      - name: Test mutation\n        if: ${{ matrix.node == '24.4.1' }}\n        run: pnpm run test:mutation\n        env:\n          BRANCH_NAME: ${{ steps.extract-branch.outputs.branch }}\n          STRYKER_DASHBOARD_API_KEY: ${{ secrets.STRYKER_TOKEN }}\n      - name: Test E2E\n        run: pnpm run test:e2e\n        id: test-e2e\n      - name: Upload E2E tests screenshots\n        if: ${{ always() && steps.test-e2e.outcome == 'failure' }}\n        uses: actions/upload-artifact@v4\n        with:\n          name: e2e-screenshots-${{ matrix.node }}\n          path: test-e2e/react-app/cypress/screenshots\n          retention-days: 7\n      - name: Upload typescript E2E tests screenshots\n        if: ${{ always() && steps.test-e2e.outcome == 'failure' }}\n        uses: actions/upload-artifact@v4\n        with:\n          name: e2e-typescript-screenshots-${{ matrix.node }}\n          path: test-e2e/typescript/cypress/screenshots\n          retention-days: 7\n      - name: Upload test results\n        uses: actions/upload-artifact@v4\n        with:\n          name: coverage-${{ matrix.node }}\n          path: coverage\n          retention-days: 1\n  quality:\n    runs-on: ubuntu-latest\n    needs: test\n    env:\n      SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v4\n        with:\n          fetch-depth: 0\n      - name: Download test results\n        uses: actions/download-artifact@v4\n        with:\n          name: coverage-22.2.0\n          path: coverage\n      - name: Coveralls\n        uses: coverallsapp/github-action@master\n        with:\n          github-token: ${{ secrets.GITHUB_TOKEN }}\n      - name: SonarCloud Scan\n        if: env.SONAR_TOKEN != ''\n        uses: SonarSource/sonarqube-scan-action@v6\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/check-package-version.yml",
    "content": "name: check-package-version\non:\n  pull_request:\n    branches:\n      - master\njobs:\n  check-package-version:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v4\n      - name: Get version is new\n        id: check\n        uses: EndBug/version-check@v2.1.1\n        with:\n          diff-search: true\n          file-name: ./package.json\n          file-url: https://unpkg.com/cypress-localstorage-commands@latest/package.json\n          static-checking: localIsNew\n      - name: Check version is new\n        if: steps.check.outputs.changed != 'true'\n        run: |\n          echo \"Version not changed\"\n          exit 1\n      - name: Get version\n        id: package-version\n        uses: martinbeentjes/npm-get-version-action@v1.3.1\n      - name: Check Changelog version\n        id: changelog_reader\n        uses: mindsers/changelog-reader-action@v2.2.3\n        with:\n          version: ${{ steps.package-version.outputs.current-version }}\n          path: ./CHANGELOG.md\n      - name: Read version from Sonar config\n        id: sonar-version\n        uses: christian-draeger/read-properties@1.1.1\n        with:\n          path: './sonar-project.properties'\n          properties: 'sonar.projectVersion'\n      - name: Check Sonar version\n        if: steps.sonar-version.outputs.sonar-projectVersion != steps.package-version.outputs.current-version\n        run: |\n          echo \"Version not changed\"\n          exit 1\n"
  },
  {
    "path": ".github/workflows/publish-to-github.yml",
    "content": "name: publish-to-github\non:\n  release:\n    types: [created]\njobs:\n  publish:\n    runs-on: ubuntu-latest\n    steps:\n    - name: Checkout\n      uses: actions/checkout@v4\n    # Setup .npmrc file to publish to GitHub Packages\n    - name: Install pnpm\n      uses: pnpm/action-setup@v4\n    - name: Install Node.js\n      uses: actions/setup-node@v4\n      with:\n        node-version: \"22.x\"\n        registry-url: 'https://npm.pkg.github.com'\n        # Defaults to the user or organization that owns the workflow file\n        scope: '@javierbrea'\n    - name: Change package name\n      uses: MerthinTechnologies/edit-json-action@v1\n      with:\n        filename: './package.json'\n        key: 'name'\n        value: '@javierbrea/cypress-localstorage-commands'\n    - name: Install dependencies\n      run: pnpm install\n    - name: Publish package\n      run: pnpm -r publish --no-git-checks\n      env:\n        NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/publish-to-npm.yml",
    "content": "name: publish-to-npm\non:\n  release:\n    types: [created]\njobs:\n  publish:\n    runs-on: ubuntu-latest\n    steps:\n    - name: Checkout\n      uses: actions/checkout@v4\n    - name: Install pnpm\n      uses: pnpm/action-setup@v4\n    - name: Install Node.js\n      uses: actions/setup-node@v4\n      with:\n        node-version: \"22.x\"\n        registry-url: 'https://registry.npmjs.org/'\n    - name: Install dependencies\n      run: pnpm install\n    - name: Publish package\n      run: pnpm -r publish --no-git-checks\n      env:\n        NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}\n"
  },
  {
    "path": ".gitignore",
    "content": "# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n#environment variables\n/.env\n\n# dependencies\n/node_modules\n\n# tests\n/coverage\n/dist\n\n# misc\n.DS_Store\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# ides\n.idea\n.vs\n\n# stryker temp files\n/reports\n.stryker-tmp\nstryker.conf.local.js\n\n# caches\n.eslintcache\n"
  },
  {
    "path": ".husky/.gitignore",
    "content": "_\n"
  },
  {
    "path": ".husky/pre-commit",
    "content": "pnpm run lint-staged\n"
  },
  {
    "path": ".vscode/settings.json",
    "content": "{\n  \"sonarlint.connectedMode.project\": {\n      \"connectionId\": \"javierbrea\",\n      \"projectKey\": \"javierbrea_cypress-localstorage-commands\"\n  }\n}\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Change Log\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Changelog](http://keepachangelog.com/)\nand this project adheres to [Semantic Versioning](http://semver.org/).\n\n## [unreleased]\n### Added\n### Changed\n### Fixed\n### Removed\n\n## [2.3.0] - 2026-03-16\n\n### Added\n\n- feat(#571): Migrate from Cypress.env() to Cypress.expose() to check whether node events are installed. Add backward compatibility for Cypress versions minor than 15.10.0 (continuing using Cypress.env() in those versions).\n\n### Changed\n\n- test: Update latest Cypress version in E2E tests to v15.10.0. Add E2E tests for Cypress v14.5.3 to check backward compatibility with Cypress.env() configuration method.\n- refactor: Fix minor Sonar issues.\n- chore(deps): Upgrade devDependencies\n- chore: Run linter, check spelling and check types only in the latest Node version in build workflow\n\n## [2.2.8] - 2025-07-28\n\n### Changed\n* test: Upgrade latest Cypress version in E2E tests to v14\n* chore(deps): Upgrade dev dependencies\n* chore(deps): Remove Node 18 from workflows. Add Node 24\n* chore(deps): Add pnpm as package manager to package.json. Remove pnpm version from workflows\n\n## [2.2.7] - 2024-12-06\n\n### Added\n* chore: Check spelling in build workflow\n\n### Changed\n* chore: Use Pnpm as package manager\n* chore: Upgrade eslint configuration to v9\n* chore: Update devDependencies\n\n### Fixed\n* docs: Fix typos in README\n\n## [2.2.6] - 2024-05-17\n\n### Added\n* chore: Handle jobs concurrency in build workflow\n\n### Changed\n* chore: Remove usage of \"set-output\" in build workflow\n* chore(deps): Update devDependencies\n\n## [2.2.5] - 2023-11-15\n\n### Changed\n- chore(deps): Update devDependencies\n\n## [2.2.4] - 2023-08-14\n\n### Changed\n- chore(deps): Update devDependencies\n\n## [2.2.3] - 2023-04-03\n\n### Changed\n- chore(deps): Update devDependencies\n\n## [2.2.2] - 2022-12-07\n\n### Added\n- docs: Add alternatives\n\n### Changed\n- chore(deps): Update devDependencies\n- test(e2e): Rename cypress-10 folder to cypress-latest\n- test(e2e): Use Cypress 12 in E2E tests\n\n## [2.2.1] - 2022-08-30\n\n### Changed\n- chore(deps): Update devDependencies\n\n## [2.2.0] - 2022-07-26\n\n### Added\n- feat(#401): Support preserving localStorage across spec files. Node events must be installed to support this feature.\n\n### Changed\n- docs: Update docs with installation method in Cypress v10. Add notes about installing it in prior versions.\n- chore(deps): Update devDependencies\n- test(e2e): Add E2E tests using different Cypress versions\n\n## [2.1.0] - 2022-06-02\n\n### Changed\n- chore: Update Cypress devDependency to v10\n- test: Use Cypress v10 for running plugin e2e tests. Update configuration.\n- chore: Update github actions versions\n\n## [2.0.0] - 2022-05-30\n\n### Removed\n- chore: Drop NodeJs 12 support\n- docs: Remove Fossa badge\n\n### Changed\n- chore: Remove NodeJs v12 from tests workflow. Add NodeJs v18\n- chore(deps): Update devDependencies\n\n## [1.7.0] - 2022-02-22\n\n### Added\n- feat(#376): Support multiple snapshots allowing to define a name in save, restore and clear commands.\n- chore: Add command to check types. Run it in build workflow\n- chore: Add eslint plugins\n\n### Removed\n- docs: Remove broken dependencies badge\n\n### Changed\n- chore: Remove NodeJs v15 from tests workflow. Add NodeJs v17\n- chore(deps): Update devDependencies\n\n## [1.6.1] - 2021-11-11\n### Changed\n- chore(#382): Use Cypress v9 in E2E tests\n- chore(#382): Support any Cypress version greater than 2.1.0\n- chore(deps): Update devDependencies\n\n## [1.6.0] - 2021-11-01\n### Changed\n- chore(deps): Update devDependencies\n- chore(deps): Support any NodeJs version greater than 10.x.\n\n## [1.5.0] - 2021-07-21\n### Added\n- chore(#330): Use Cypress v8 in E2E tests. Add Cypress v8.x to peerDependencies\n\n### Changed\n- chore(deps): Update devDependencies\n\n## [1.4.5] - 2021-05-29\n\n### Changed\n- chore(deps): Update devDependencies\n- chore: Migrate Sonar project\n\n## [1.4.4] - 2021-04-29\n\n### Added\n- chore(deps): Support Node v16.x in engines. Run tests also in node 16.0.0\n\n### Changed\n- chore(deps): Update devDependencies\n\n## [1.4.3] - 2021-04-07\n\n### Added\n- chore(deps): Support Cypress v7.x in peerDependencies\n\n### Changed\n- test(e2e): Run e2e tests in Cypress v7.x\n- chore(pipelines): Update node versions\n- chore(pipelines): Do not run tests in Node 10, because it is not supported by Cypress v7.x\n- chore(deps): Update devDependencies\n\n## [1.4.2] - 2021-03-31\n\n### Changed\n- chore(deps): Update devDependencies\n\n## [1.4.1] - 2021-02-24\n\n### Changed\n- chore(deps): Update devDependencies\n- test: Refactor Sonar smells\n\n## [1.4.0] - 2021-01-17\n\n### Added\n- chore: Add types property to package.json (#232)\n\n### Changed\n- chore(deps): Update devDependencies\n- test(e2e): Adapt testing react app code to [data-provider v3](https://www.data-provider.org/docs/guides-migrating-from-v2-to-v3)\n\n## [1.3.1] - 2020-12-11\n\n### Changed\n- chore(#210): Support all Node.js releases that have not passed their end date\n- chore(deps): Update devDependencies\n- chore(ci): Do not execute SonarCloud on PRs from forks\n\n### Fixed\n- docs(readme): Fix build badge url\n\n## [1.3.0] - 2020-12-07\n\n### Added\n- feat(#191): Add disableLocalStorage command (Thanks to @Uninen for his contribution).\n\n### Changed\n- chore(deps): Update some devDependencies\n\n### Fixed\n- style(lint): Lint also files in root folder. Fix jest.config style\n\n## [1.2.5] - 2020-12-05\n\n### Changed\n- chore(ci): Migrate CI to github actions. Rename npm commands\n- chore(deps): Add Cypress 6.x to peerDependencies\n- chore(test): Update Cypress to v6.0.1 in e2e tests\n- chore(deps): Update devDependencies\n\n## [1.2.4] - 2020-10-29\n\n### Added\n- chore(deps): Add node engine dep option for node@v15.x\n\n### Changed\n- chore(deps): Update devDependencies\n\n## [1.2.3] - 2020-10-19\n\n### Changed\n- chore(deps): Update devDependencies\n- test(cypress): Do not use \"be\" as assertion in Cypress tests as it is no longer supported\n- chore(deps): Modify Stryker config to adapt it to Stryker 4.0 version\n\n## [1.2.2] - 2020-08-27\n\n### Changed\n- chore(deps): Add Cypress ^5.0.0 to peerDependencies\n- chore(deps): Update devDependencies\n\n## [1.2.1] - 2020-06-09\n\n### Fixed\n- fix(TypeScript): Fix TypeScript return types declarations\n\n### Changed\n- chore(deps): Update devDependencies\n\n## [1.2.0] - 2020-05-31\n\n### Added\n- feat(TypeScript): Add TypeScript support\n\n## [1.1.10] - 2020-05-16\n\n### Added\n- tests(stryker): Add Stryker-mutator tests\n\n### Changed\n- chore(deps): Update devDependencies\n\n## [1.1.9] - 2020-04-28\n\n### Changed\n- chore(deps): Allow node.js v14\n- chore(deps): Update devDependencies\n\n## [1.1.8] - 2020-04-09\n\n### Changed\n- chore(deps): Update devDependencies\n\n## [1.1.7] - 2020-03-22\n### Changed\n- chore(deps): Update devDependencies\n\n## [1.1.6] - 2020-02-19\n### Changed\n- chore(deps): Add Cypress ^4.0.0 to peerDependencies\n- chore(test): Update Cypress to v4.0.2 in e2e tests\n- chore(deps): Update eslint-plugin-react and husky devDependencies\n- chore(test): Update react-scripts devDependency in e2e tests\n- docs(readme): Fix typo\n\n## [1.1.5] - 2020-02-01\n### Changed\n- Update devDependencies\n\n## [1.1.4] - 2020-01-13\n### Changed\n- Use fixed versions in e2e tests dependencies\n\n## [1.1.3] - 2020-01-13\n### Changed\n- Use fixed versions in dependencies\n\n## [1.1.2] - 2020-01-11\n### Changed\n- Upgrade dependencies\n- Disable temporarily Sonar as it is under maintenance\n\n## [1.1.1] - 2019-12-28\n### Changed\n- Upgrade dependencies.\n- Rename acceptance tests into e2e tests.\n- Improve documentation examples.\n\n### Added\n- Add npm command for running e2e tests.\n- Add e2e tests to check that examples works.\n\n## [1.1.0] - 2019-10-27\n### Added\n- Add getLocalStorage command\n- Add setLocalStorage command\n- Add removeLocalStorage command\n- Add acceptance tests\n\n### Changed\n- Improve documentation\n\n## [1.0.0] - 2019-10-26\n### Added\n- Add saveLocalStorage command\n- Add restoreLocalStorage command\n- Add clearLocalStorageSnapshot command\n\n## [1.0.0-alpha.1] - 2019-10-26\n### Added\n- Add package structure.\n- Package still not functional.\n- Reserve npm package name.\n\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2019-2024 Javier Brea\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "[![Build status][build-image]][build-url] [![Coverage Status][coveralls-image]][coveralls-url] [![Quality Gate][quality-gate-image]][quality-gate-url] [![Mutation testing status][mutation-image]][mutation-url]\n\n[![Renovate](https://img.shields.io/badge/renovate-enabled-brightgreen.svg)](https://renovatebot.com) [![Last commit][last-commit-image]][last-commit-url] [![Last release][release-image]][release-url]\n\n[![NPM downloads][npm-downloads-image]][npm-downloads-url] [![License][license-image]][license-url]\n\n# Cypress localStorage commands\n\nExtends Cypress' cy commands with localStorage methods. Allows preserving localStorage between tests and spec files, and disabling localStorage.\n\n## The problems\n\n* You want to preserve localStorage between Cypress tests.\n* You want to preserve localStorage between Cypress spec files.\n* You want to disable localStorage to check error handling.\n\n## This solution\n\nThis solution allows you to use all browser localStorage methods through Cypress commands, and preserve it between tests and spec files. It also allows to simulate that localStorage is disabled in the browser.\n\n## Alternatives\n\nAs from Cypress 12, you can use [`cy.session`](https://docs.cypress.io/api/commands/session) and [Cypress Test Isolation](https://docs.cypress.io/guides/core-concepts/test-isolation) in order to persist localStorage between tests. __Anyway, this plugin can be still used for an easier manipulation of the localStorage, writing localStorage assertions and even disabling it for checking the error handling.__\n\n## Installation\n\nThis module is distributed via npm which is bundled with node and should be installed as one of your project's devDependencies:\n\n```bash\nnpm i --save-dev cypress-localstorage-commands\n```\n\n### Installing commands\n\n`cypress-localstorage-commands` extends Cypress' cy commands.\n\nAt the top of your Cypress' support file (usually `cypress/support/e2e.js` for `e2e` testing type):\n\n```javascript\nimport \"cypress-localstorage-commands\";\n```\n\nRead [Cypress configuration docs](https://docs.cypress.io/guides/references/configuration) for further info.\n\n<details>\n<summary><strong>Installing commands in Cypress <10.0</strong></summary>\n\nAdd this line to your project's `cypress/support/index.js`:\n\n```js\nimport \"cypress-localstorage-commands\"\n```\n\n</details>\n\n### Installing Node events\n\n__⚠ In order to support preserving localStorage across Cypress spec files, the plugin's Node events must be installed also.__ Otherwise, localStorage will be preserved only across tests in the same spec file.\n\nIn the `cypress.config.js` file:\n\n```javascript\nmodule.exports = {\n  e2e: {\n    setupNodeEvents(on, config) {\n      require(\"cypress-localstorage-commands/plugin\")(on, config);\n      return config;\n    },\n  },\n};\n```\n\n<details>\n<summary><strong>Installing Node events in Cypress <10.0</strong></summary>\n\nIn the `cypress/plugins/index.js` file:\n\n```javascript\nmodule.exports = (on, config) => {\n  require(\"cypress-localstorage-commands/plugin\")(on, config);\n  return config;\n};\n```\n\n</details>\n\n## Usage\n\n### Commands\n\n#### `cy.saveLocalStorage([snapshotName])`\n\nSaves current localStorage values into an internal \"snapshot\".\n\n* `snapshotName` _(String)_: Optionally, a `snapshotName` can be provided, and then data from localStorage will be saved into a snapshot with that name. So, multiple snapshots can be stored.\n\n#### `cy.restoreLocalStorage([snapshotName])`\n\nRestores localStorage to previously \"snapshot\" saved values. __\n\n* `snapshotName` _(String)_: Optional. If provided, the localStorage will be restored using data from that specific snapshot.\n\n#### `cy.clearLocalStorageSnapshot([snapshotName])`\n\nClears localStorage \"snapshot\" values, so previously saved values are cleaned.\n\n* `snapshotName` _(String)_: Optional. If provided, only data from that specific snapshot will be cleared.\n\n#### `cy.getLocalStorage(item)`\n\nGets localStorage item. Equivalent to `localStorage.getItem` in browser.\n\n* `item` _(String)_: Item to get from `localStorage`.\n\n#### `cy.setLocalStorage(item, value)`\n\nSets localStorage item. Equivalent to `localStorage.setItem` in browser.\n\n* `item` _(String)_: Item to set value.\n* `value` _(String)_: Value to be set.\n\n#### `cy.removeLocalStorage(item)`\n\nRemoves localStorage item. Equivalent to `localStorage.removeItem` in browser.\n\n* `item` _(String)_: Item to be removed.\n\n#### `cy.disableLocalStorage(options)`\n\nDisables localStorage. It produces localStorage methods to throw errors.\n\n* `options` _(Object)_: Options to use when disabling `localStorage`.\n  * `withError` _(Error)_: If provided, invocations to `localStorage` methods will throw this error.\n\n### Preserving local storage between tests\n\nUse `cy.saveLocalStorage()` to save a snapshot of current `localStorage` at the end of one test, and use the `cy.restoreLocalStorage()` command to restore it at the beginning of another one. _The usage of `beforeEach` and `afterEach` is recommended for this purpose._\n\n> ⚠ When the [plugin's Node events are installed](#installing-node-events), the `cy.restoreLocalStorage()` command will be able to restore the localStorage snapshots saved in other spec files. Otherwise, snapshots are completely cleared between spec files.\n\n### Examples\n\n#### Cookies button example\n\nNext example shows how this package can be used to test a \"cookies button\" _(which in theory sets a flag into `localStorage` and can be clicked only once)_\n\n```js\ndescribe(\"Accept cookies button\", () => {\n  const COOKIES_BUTTON = \"#accept-cookies\";\n\n  before(() => {\n    cy.clearLocalStorageSnapshot();\n  });\n\n  beforeEach(() => {\n    cy.restoreLocalStorage();\n    cy.visit(\"/\");\n  });\n\n  afterEach(() => {\n    cy.saveLocalStorage();\n  });\n\n  it(\"should be visible\", () => {\n    cy.get(COOKIES_BUTTON).should(\"be.visible\");\n  });\n\n  it(\"should not be visible after clicked\", () => {\n    cy.get(COOKIES_BUTTON).click();\n    cy.get(COOKIES_BUTTON).should(\"not.be.visible\");\n  });\n\n  it(\"should not be visible after reloading\", () => {\n    cy.get(COOKIES_BUTTON).should(\"not.be.visible\");\n  });\n});\n```\n\n> Note the usage of `beforeEach` and `afterEach` for preserving `localStorage` between all tests. Also `cy.clearLocalStorageSnapshot` is used in the `before` statement to avoid possible conflicts with other spec files preserving localStorage.\n\n#### localStorage assertions\n\nBased on the previous example, assertions could be added to check values of `localStorage`:\n\n```js\ndescribe(\"localStorage cookies-accepted item\", () => {\n  beforeEach(() => {\n    cy.restoreLocalStorage();\n    cy.visit(\"/\");\n  });\n\n  afterEach(() => {\n    cy.saveLocalStorage();\n  });\n\n  it(\"should be null first time page is visited\", () => {\n    cy.getLocalStorage(\"cookies-accepted\").should(\"equal\", null);\n  });\n\n  it(\"should be true after clicking cookies button\", () => {\n    cy.get(\"#accept-cookies\").click();\n    cy.getLocalStorage(\"cookies-accepted\").should(\"equal\", \"true\");\n  });\n\n  it(\"should be true after reloading\", () => {\n    cy.getLocalStorage(\"cookies-accepted\").then(cookiesAccepted => {\n      expect(cookiesAccepted).to.equal(\"true\");\n    });\n  });\n});\n```\n\n#### Named snapshots\n\nNext example shows how named snapshots can be used to storage different states of `localStorage` and restore one or another depending of the test:\n\n```js\ndescribe(\"Accept cookies button\", () => {\n  const COOKIES_BUTTON = \"#accept-cookies\";\n\n  before(() => {\n    cy.clearLocalStorageSnapshot();\n  });\n\n  it(\"should be visible\", () => {\n    cy.visit(\"/\");\n    cy.get(COOKIES_BUTTON).should(\"be.visible\");\n    cy.saveLocalStorage(\"cookies-not-accepted\");\n  });\n\n  it(\"should not exist after clicked\", () => {\n    cy.get(COOKIES_BUTTON).click();\n    cy.get(COOKIES_BUTTON).should(\"not.exist\");\n    cy.saveLocalStorage(\"cookies-accepted\");\n  });\n\n  it(\"should be visible when cookies are not accepted\", () => {\n    cy.restoreLocalStorage(\"cookies-not-accepted\");\n    cy.visit(\"/\");\n    cy.get(COOKIES_BUTTON).should(\"be.visible\");\n  });\n\n  it(\"should not exist when cookies are accepted\", () => {\n    cy.restoreLocalStorage(\"cookies-accepted\");\n    cy.visit(\"/\");\n    cy.get(COOKIES_BUTTON).should(\"not.exist\");\n  });\n});\n```\n\n### Disabling localStorage\n\nUse `cy.disableLocalStorage()` to simulate that `localStorage` is disabled, producing that any invocation to `localStorage.setItem`, `localStorage.getItem`, `localStorage.removeItem` or `localStorage.clear` will throw an error. [As MDN docs recommend](https://developer.mozilla.org/en-US/docs/Web/API/Storage/setItem), _\"developers should make sure to always catch possible exceptions from setItem()\"_. This command allows to test that possible exceptions are handled correctly.\n\nNote that:\n\n* Only pages loaded after calling this command will have `localStorage` disabled, so always use `cy.reload` or `cy.visit` after executing it.\n* The `localStorage` only remains disabled for all pages loaded during the current test. If you want to disable it for multiple tests, execute it in all of them, or in a `beforeEach` statement.\n* If any of the other plugin commands (except `clearLocalStorageSnapshot`) is executed while `localStorage` is disabled, it will do nothing but producing a Cypress log as: _\"localStorage.setItem is disabled\"_\n\n### Examples\n\n#### Disabling localStorage in a single test\n\nBased on previous \"Accept cookies button\" example, next tests could be added:\n\n```js\n//...\nconst LOCALSTORAGE_DISABLED_WARNING = \"#localstorage-disabled-warning\";\nconst LOCALSTORAGE_ERROR = \"#localstorage-error\";\n\n//... should not be visible after clicked\n\nit(\"should still be visible when reloading if localStorage is disabled\", () => {\n  cy.disableLocalStorage();\n  cy.reload();\n  cy.get(COOKIES_BUTTON).should(\"be.visible\");\n});\n\nit(\"should display warning if localStorage is disabled\", () => {\n  cy.disableLocalStorage();\n  cy.reload();\n  cy.get(LOCALSTORAGE_DISABLED_WARNING).should(\"be.visible\");\n});\n\nit(\"should display localStorage error message\", () => {\n  cy.disableLocalStorage();\n  cy.reload();\n  cy.get(LOCALSTORAGE_ERROR).should(\"have.text\", \"Error\");\n});\n\n// ...should not be visible after reloading\n```\n\n#### Disabling localStorage in multiple tests\n\n```js\ndescribe(\"when localStorage is disabled\", () => {\n  beforeEach(() => {\n    cy.disableLocalStorage({\n      withError: new Error(\"Disabled by cypress-localstorage-commands\"),\n    });\n    cy.visit(\"/\");\n  });\n\n  it(\"should display localStorage warning\", () => {\n    cy.get(\"#localstorage-disabled-warning\").should(\"be.visible\");\n  });\n\n  it(\"should display localStorage error message\", () => {\n    cy.get(\"#localstorage-error\").should(\"have.text\", \"Disabled by cypress-localstorage-commands\");\n  });\n\n  it(\"should display accept-cookies button disabled\", () => {\n    cy.get(\"#accept-cookies\").should(\"be.disabled\");\n  });\n});\n```\n\n## Usage with TypeScript\n\nFor those writing [TypesScript tests in Cypress][cypress-typescript], this package includes TypeScript declarations.\n\nAdd \"cypress-localstorage-commands\" to the `types` property of the `tsconfig.json` file:\n\n```json\n{\n  \"compilerOptions\": {\n    \"types\": [\"cypress\", \"cypress-localstorage-commands\"]\n  }\n}\n```\n\nOr reference the package in the files using it:\n\n```typescript\n/// <reference types=\"cypress-localstorage-commands\" />\n```\n\n## Contributing\n\nContributors are welcome.\nPlease read the [contributing guidelines](.github/CONTRIBUTING.md) and [code of conduct](.github/CODE_OF_CONDUCT.md).\n\n## License\n\nMIT, see [LICENSE](./LICENSE) for details.\n\n[coveralls-image]: https://coveralls.io/repos/github/javierbrea/cypress-localstorage-commands/badge.svg\n[coveralls-url]: https://coveralls.io/github/javierbrea/cypress-localstorage-commands\n[build-image]: https://github.com/javierbrea/cypress-localstorage-commands/workflows/build/badge.svg?branch=master\n[build-url]: https://github.com/javierbrea/cypress-localstorage-commands/actions?query=workflow%3Abuild+branch%3Amaster\n[mutation-image]: https://img.shields.io/endpoint?style=flat&url=https%3A%2F%2Fbadge-api.stryker-mutator.io%2Fgithub.com%2Fjavierbrea%2Fcypress-localstorage-commands%2Fmaster\n[mutation-url]: https://dashboard.stryker-mutator.io/reports/github.com/javierbrea/cypress-localstorage-commands/master\n[last-commit-image]: https://img.shields.io/github/last-commit/javierbrea/cypress-localstorage-commands.svg\n[last-commit-url]: https://github.com/javierbrea/cypress-localstorage-commands/commits\n[license-image]: https://img.shields.io/npm/l/cypress-localstorage-commands.svg\n[license-url]: https://github.com/javierbrea/cypress-localstorage-commands/blob/master/LICENSE\n[npm-downloads-image]: https://img.shields.io/npm/dm/cypress-localstorage-commands.svg\n[npm-downloads-url]: https://www.npmjs.com/package/cypress-localstorage-commands\n[quality-gate-image]: https://sonarcloud.io/api/project_badges/measure?project=javierbrea_cypress-localstorage-commands&metric=alert_status\n[quality-gate-url]: https://sonarcloud.io/dashboard?id=javierbrea_cypress-localstorage-commands\n[release-image]: https://img.shields.io/github/release-date/javierbrea/cypress-localstorage-commands.svg\n[release-url]: https://github.com/javierbrea/cypress-localstorage-commands/releases\n\n[cypress-typescript]: https://docs.cypress.io/guides/tooling/typescript-support.html\n"
  },
  {
    "path": "cspell/missing.txt",
    "content": "Brea\ncommonmark\ncoverallsapp\njavierbrea\nMerthin\nprelint\nsonarcloud\nsonarqube\nsonarsource\nUninen\n"
  },
  {
    "path": "cspell.config.js",
    "content": "const { resolve } = require(\"node:path\");\n\nconst DICTIONARIES_BASE_PATH = resolve(__dirname, \"cspell\");\n\nmodule.exports = {\n  // Version of the setting file.  Always 0.2\n  version: \"0.2\",\n  // Paths to be ignored\n  ignorePaths: [\n    \"**/node_modules/**\",\n    \".husky/**\",\n    \"**/pnpm-lock.yaml\",\n    \"**/cspell/*.txt\",\n    \"cspell.config.js\",\n    \"**/.gitignore\",\n    \"**/coverage/**\",\n    \"**/dist/**\",\n    \"test-e2e/app/build/**\",\n    \"test-e2e/*/cypress/integration/**\",\n    \"test-e2e/app/build/**\",\n    \"test-e2e/cypress-typescript/cypress/support/cypress-localstorage-commands/**\",\n    \"reports/**\",\n  ],\n  caseSensitive: false,\n  // Language - current active spelling language\n  language: \"en\",\n  // Dictionaries to be used\n  dictionaryDefinitions: [\n    {\n      name: \"missing\",\n      path: `${DICTIONARIES_BASE_PATH}/missing.txt`,\n    },\n  ],\n  dictionaries: [\"missing\"],\n  languageSettings: [\n    {\n      // In markdown files\n      languageId: \"markdown\",\n      // Exclude code blocks from spell checking\n      ignoreRegExpList: [\"/^\\\\s*```[\\\\s\\\\S]*?^\\\\s*```/gm\"],\n    },\n  ],\n  // The minimum length of a word before it is checked.\n  minWordLength: 4,\n  // cspell:disable-next-line FlagWords - list of words to be always considered incorrect. This is useful for offensive words and common spelling errors. For example \"hte\" should be \"the\"\n  flagWords: [\"hte\"],\n};\n"
  },
  {
    "path": "eslint.config.mjs",
    "content": "import json from \"@eslint/json\";\nimport markdown from \"@eslint/markdown\";\nimport prettier from \"eslint-plugin-prettier\";\nimport eslintPluginPrettierRecommended from \"eslint-plugin-prettier/recommended\";\nimport eslintConfigPrettier from \"eslint-config-prettier\";\nimport js from \"@eslint/js\";\nimport globals from \"globals\";\n// eslint-disable-next-line import/no-unresolved\nimport typescriptParser from \"@typescript-eslint/parser\";\n// eslint-disable-next-line import/no-unresolved\nimport typescriptEslintPlugin from \"@typescript-eslint/eslint-plugin\";\nimport pluginJest from \"eslint-plugin-jest\";\nimport importPlugin from \"eslint-plugin-import\";\n// eslint-disable-next-line import/no-unresolved\nimport pluginCypress from \"eslint-plugin-cypress/flat\";\nimport reactPlugin from \"eslint-plugin-react\";\n\nexport default [\n  {\n    ignores: [\n      \"**/node_modules/**\",\n      \".husky/**\",\n      \"dist/**\",\n      \"test-e2e/*/cypress/integration/**\",\n      \"test-e2e/app/build/**\",\n      \"test-e2e/cypress-typescript/cypress/support/cypress-localstorage-commands/**\",\n      \"reports/**\",\n    ],\n  },\n  {\n    files: [\"**/*.json\"],\n    language: \"json/json\",\n    plugins: {\n      json,\n    },\n    rules: {\n      \"json/no-duplicate-keys\": \"error\",\n      \"json/no-empty-keys\": \"error\",\n    },\n  },\n  {\n    files: [\"**/*.md\"],\n    plugins: {\n      markdown,\n    },\n    language: \"markdown/commonmark\",\n    rules: {\n      \"markdown/no-html\": [0],\n    },\n  },\n  {\n    files: [\n      \"**/*.js\",\n      \"**/*.cjs\",\n      \"**/*.mjs\",\n      \"**/*.jsx\",\n      \"**/*.ts\",\n      \"**/*.tsx\",\n    ],\n    plugins: {\n      prettier,\n      import: importPlugin,\n    },\n    languageOptions: {\n      ecmaVersion: \"latest\",\n      sourceType: \"module\",\n      globals: {\n        ...globals.node,\n      },\n    },\n    rules: {\n      ...importPlugin.flatConfigs.recommended.rules,\n      ...js.configs.recommended.rules,\n      ...eslintConfigPrettier.rules,\n      ...eslintPluginPrettierRecommended.rules,\n      camelcase: [2, { properties: \"never\" }],\n      \"no-console\": [2, { allow: [\"warn\", \"error\"] }],\n      \"no-shadow\": [2, { builtinGlobals: true, hoist: \"all\" }],\n      \"no-undef\": [2],\n      \"no-unused-vars\": [\n        2,\n        { vars: \"all\", args: \"after-used\", ignoreRestSiblings: false },\n      ],\n    },\n  },\n  {\n    files: [\"**/*.cjs\"],\n    languageOptions: {\n      ecmaVersion: \"latest\",\n      sourceType: \"commonjs\",\n    },\n  },\n  {\n    files: [\"**/*.ts\"],\n    languageOptions: {\n      parser: typescriptParser,\n      parserOptions: {\n        projectService: true,\n      },\n    },\n    plugins: {\n      \"@typescript-eslint\": typescriptEslintPlugin,\n    },\n    rules: {\n      ...typescriptEslintPlugin.configs.recommended.rules,\n    },\n    settings: {\n      \"import/resolver\": {\n        typescript: {\n          extensions: [\".ts\", \".tsx\"],\n          alwaysTryTypes: true,\n        },\n        node: true,\n      },\n    },\n  },\n  {\n    files: [\"**/plugin.d.ts\"],\n    languageOptions: {\n      globals: {\n        Cypress: \"readonly\",\n      },\n    },\n  },\n  {\n    files: [\"test/**/*.spec.js\"],\n    plugins: {\n      jest: pluginJest,\n    },\n    ...pluginJest.configs[\"flat/recommended\"],\n    languageOptions: {\n      globals: pluginJest.environments.globals.globals,\n    },\n    rules: {\n      ...pluginJest.configs[\"flat/recommended\"].rules,\n      \"jest/no-disabled-tests\": \"error\",\n      \"jest/no-focused-tests\": \"error\",\n      \"jest/no-identical-title\": \"error\",\n      \"jest/prefer-to-have-length\": \"error\",\n      \"jest/valid-expect\": \"error\",\n      \"jest/prefer-strict-equal\": [0],\n      \"jest/prefer-importing-jest-globals\": [0],\n      \"jest/prefer-expect-assertions\": [0],\n      \"jest/no-hooks\": [0],\n      \"jest/prefer-called-with\": [0],\n      \"jest/require-to-throw-message\": [0],\n    },\n  },\n  {\n    files: [\"test-e2e/app/src/**/*.js\"],\n    plugins: {\n      react: reactPlugin,\n    },\n    ...reactPlugin.configs.flat.recommended,\n    languageOptions: {\n      ...reactPlugin.configs.flat.recommended.languageOptions,\n      globals: {\n        ...globals.browser,\n      },\n    },\n    settings: {\n      react: {\n        pragma: \"React\",\n        version: \"^17.0.0\",\n      },\n    },\n    rules: {\n      \"react/jsx-uses-react\": \"error\",\n      \"react/jsx-uses-vars\": \"error\",\n      \"react/react-in-jsx-scope\": \"off\",\n    },\n  },\n  {\n    files: [\"**/*.cy.js\", \"**/*.cy.ts\"],\n    plugins: {\n      cypress: pluginCypress,\n    },\n    ...pluginCypress.configs.recommended,\n  },\n  // TODO: Add config for cypress tests\n];\n"
  },
  {
    "path": "index.d.ts",
    "content": "/// <reference types=\"cypress\" />\n\ndeclare namespace Cypress {\n  interface Chainable {\n    /**\n     * Command to save current localStorage values into an internal \"snapshot\"\n     * @param {string} snapshotName - Name of the snapshot\n     * @example cy.saveLocalStorage()\n     */\n    saveLocalStorage(snapshotName?: string): Chainable<undefined>;\n\n    /**\n     * Command to restore localStorage to previously \"snapshot\" saved values\n     * @param {string} snapshotName - Name of the snapshot\n     * @example cy.restoreLocalStorage()\n     */\n    restoreLocalStorage(snapshotName?: string): Chainable<undefined>;\n\n    /**\n     * Command to clear localStorage \"snapshot\" values\n     * @param {string} snapshotName - Name of the snapshot\n     * @example cy.clearLocalStorageSnapshot()\n     */\n    clearLocalStorageSnapshot(snapshotName?: string): Chainable<undefined>;\n\n    /**\n     * Command to get localStorage item value\n     * @param {string} itemKeyName - localStorage item to get\n     * @example cy.getLocalStorage(\"cookies-accepted\")\n     */\n    getLocalStorage(itemKeyName: string): Chainable<string | null>;\n\n    /**\n     * Command to set localStorage item value\n     * @param {string} itemKeyName - localStorage item to set\n     * @param {string} value - value to be set\n     * @example cy.setLocalStorage(\"cookies-accepted\", \"true\")\n     */\n    setLocalStorage(itemKeyName: string, value: string): Chainable<undefined>;\n\n    /**\n     * Command to remove localStorage item\n     * @param {string} itemKeyName - localStorage item to remove\n     * @example cy.removeLocalStorage(\"cookies-accepted\")\n     */\n    removeLocalStorage(itemKeyName: string): Chainable<undefined>;\n\n    /**\n     * Command to disable localStorage\n     * @param {object} options - Options for disabling localStorage\n     * @example cy.disableLocalStorage()\n     */\n    disableLocalStorage(options?: { withError: Error }): Chainable<undefined>;\n  }\n}\n"
  },
  {
    "path": "index.js",
    "content": "/* global Cypress, cy, localStorage */\n\nconst { register } = require(\"./src/register\");\n\nregister(Cypress, cy, localStorage);\n"
  },
  {
    "path": "jest.config.js",
    "content": "// For a detailed explanation regarding each configuration property, visit:\n// https://jestjs.io/docs/en/configuration.html\n\nmodule.exports = {\n  // Automatically clear mock calls and instances between every test\n  clearMocks: true,\n\n  // Indicates whether the coverage information should be collected while executing the test\n  collectCoverage: true,\n\n  // An array of glob patterns indicating a set of files for which coverage information should be collected\n  collectCoverageFrom: [\"src/**\"],\n\n  // The directory where Jest should output its coverage files\n  coverageDirectory: \"coverage\",\n\n  // An object that configures minimum threshold enforcement for coverage results\n  coverageThreshold: {\n    global: {\n      branches: 100,\n      functions: 100,\n      lines: 100,\n      statements: 100,\n    },\n  },\n\n  // The test environment that will be used for testing\n  testEnvironment: \"node\",\n\n  // The glob patterns Jest uses to detect test files\n  testMatch: [\"**/test/**/*.spec.js\"],\n};\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"cypress-localstorage-commands\",\n  \"version\": \"2.3.0\",\n  \"description\": \"Extends Cypress' cy commands with localStorage methods. Allows preserving localStorage between tests\",\n  \"keywords\": [\n    \"cypress\",\n    \"plugin\",\n    \"local-storage\",\n    \"localstorage\",\n    \"methods\",\n    \"utilities\",\n    \"commands\",\n    \"testing-tools\",\n    \"testing\",\n    \"persistence\"\n  ],\n  \"author\": \"Javier Brea\",\n  \"license\": \"MIT\",\n  \"repository\": \"https://github.com/javierbrea/cypress-localstorage-commands\",\n  \"files\": [\n    \"src\",\n    \"index.d.ts\",\n    \"plugin.js\",\n    \"plugin.d.ts\"\n  ],\n  \"main\": \"index.js\",\n  \"types\": \"index.d.ts\",\n  \"scripts\": {\n    \"cspell\": \"cspell . --quiet\",\n    \"lint\": \"eslint .\",\n    \"lint-staged\": \"lint-staged\",\n    \"test\": \"jest\",\n    \"test:ci\": \"pnpm run test:unit && pnpm run test:mutation && pnpm run test:e2e\",\n    \"test:e2e\": \"pnpm test:e2e:cypress-9 && pnpm test:e2e:cypress-9-no-plugin && pnpm test:e2e:cypress-14 && pnpm test:e2e:cypress-14-no-plugin && pnpm test:e2e:cypress-latest && pnpm test:e2e:cypress-latest-no-plugin && pnpm test:e2e:cypress-typescript\",\n    \"test:e2e:cypress-9\": \"pnpm --filter cypress-9 test:ci\",\n    \"test:e2e:cypress-9-no-plugin\": \"pnpm --filter cypress-9-no-plugin test:ci\",\n    \"test:e2e:cypress-14\": \"pnpm --filter cypress-14 test:ci\",\n    \"test:e2e:cypress-14-no-plugin\": \"pnpm --filter cypress-14-no-plugin test:ci\",\n    \"test:e2e:cypress-latest\": \"pnpm --filter cypress-latest test:ci\",\n    \"test:e2e:cypress-latest-no-plugin\": \"pnpm --filter cypress-latest-no-plugin test:ci\",\n    \"test:e2e:cypress-typescript\": \"pnpm --filter cypress-typescript test:ci\",\n    \"test:mutation\": \"stryker run\",\n    \"test:unit\": \"pnpm run test\",\n    \"tsc\": \"tsc\",\n    \"prepare\": \"is-ci || husky install\"\n  },\n  \"peerDependencies\": {\n    \"cypress\": \">=2.1.0\"\n  },\n  \"devDependencies\": {\n    \"@cypress/webpack-preprocessor\": \"6.0.4\",\n    \"@eslint/js\": \"9.32.0\",\n    \"@eslint/json\": \"0.13.1\",\n    \"@eslint/markdown\": \"7.5.1\",\n    \"@stryker-mutator/core\": \"9.6.0\",\n    \"@stryker-mutator/jest-runner\": \"9.6.0\",\n    \"@typescript-eslint/eslint-plugin\": \"8.57.0\",\n    \"@typescript-eslint/parser\": \"8.57.0\",\n    \"babel-loader\": \"10.1.1\",\n    \"babel-plugin-module-resolver\": \"5.0.2\",\n    \"cspell\": \"9.7.0\",\n    \"cypress\": \"15.12.0\",\n    \"eslint\": \"9.32.0\",\n    \"eslint-config-prettier\": \"10.1.8\",\n    \"eslint-import-resolver-typescript\": \"4.4.4\",\n    \"eslint-plugin-cypress\": \"5.1.0\",\n    \"eslint-plugin-import\": \"2.32.0\",\n    \"eslint-plugin-jest\": \"29.15.0\",\n    \"eslint-plugin-prettier\": \"5.5.5\",\n    \"eslint-plugin-react\": \"7.37.5\",\n    \"fs-extra\": \"11.3.4\",\n    \"globals\": \"16.3.0\",\n    \"husky\": \"9.1.7\",\n    \"is-ci\": \"4.1.0\",\n    \"jest\": \"30.3.0\",\n    \"lint-staged\": \"16.4.0\",\n    \"prettier\": \"3.8.1\",\n    \"sinon\": \"21.0.2\",\n    \"start-server-and-test\": \"2.1.5\",\n    \"typescript\": \"5.9.3\",\n    \"webpack\": \"5.105.4\"\n  },\n  \"lint-staged\": {\n    \"**/*.js\": \"eslint\",\n    \"**/*.ts\": \"eslint\",\n    \"**/*.tsx\": \"eslint\",\n    \"**/*.json\": \"eslint\",\n    \"**/*.md\": \"eslint\",\n    \"*.*\": \"cspell --no-must-find-files\"\n  },\n  \"engines\": {\n    \"node\": \">=14.0.0\"\n  },\n  \"packageManager\": \"pnpm@9.4.0\"\n}\n"
  },
  {
    "path": "plugin.d.ts",
    "content": "/// <reference types=\"cypress\" />\n\n/**\n * Installs cypress-localstorage-commands node events\n * @example plugin(on, config);\n * @param on Cypress plugin events\n * @param config Cypress plugin config options\n * @returns Cypress plugin config options\n */\ndeclare function _exports(\n  on: Cypress.PluginEvents,\n  config: Cypress.PluginConfigOptions,\n): Cypress.PluginConfigOptions;\nexport = _exports;\n"
  },
  {
    "path": "plugin.js",
    "content": "module.exports = require(\"./src/plugin\");\n"
  },
  {
    "path": "pnpm-workspace.yaml",
    "content": "packages:\n  - \".\"\n  - \"test-e2e/app\"\n  - \"test-e2e/cypress-*\"\n"
  },
  {
    "path": "renovate.json",
    "content": "{\n  \"extends\": [\n    \"github>javierbrea/renovate-config\"\n  ],\n  \"packageRules\": [\n    {\n      \"matchPaths\": [\"test-e2e/cypress-9/package.json\"],\n      \"matchPackageNames\": [\"cypress\"],\n      \"allowedVersions\": \"9.x\"\n    },\n    {\n      \"matchPaths\": [\"test-e2e/cypress-9-no-plugin/package.json\"],\n      \"matchPackageNames\": [\"cypress\"],\n      \"allowedVersions\": \"9.x\"\n    },\n    {\n      \"matchPaths\": [\"test-e2e/cypress-latest/package.json\"],\n      \"matchPackageNames\": [\"cypress\"],\n      \"allowedVersions\": \"13.x\"\n    },\n    {\n      \"matchPaths\": [\"test-e2e/cypress-latest-no-plugin/package.json\"],\n      \"matchPackageNames\": [\"cypress\"],\n      \"allowedVersions\": \"13.x\"\n    }\n  ]\n}\n"
  },
  {
    "path": "sonar-project.properties",
    "content": "sonar.organization=javierbrea\nsonar.projectKey=javierbrea_cypress-localstorage-commands\nsonar.projectVersion=2.3.0\n\nsonar.javascript.file.suffixes=.js\nsonar.sourceEncoding=UTF-8\nsonar.exclusions=node_modules/**,test-e2e/react-app/node_modules/**\nsonar.coverage.exclusions=test/**/*,index.js,plugin.js,stryker.conf.js,jest.config.js,test-e2e/**/*,cspell.config.js,eslint.config.mjs\nsonar.cpd.exclusions=test/**/*,test-e2e/**/*\nsonar.javascript.lcov.reportPaths=coverage/lcov.info\nsonar.host.url=https://sonarcloud.io\n"
  },
  {
    "path": "src/LocalStorage.js",
    "content": "const {\n  GET_SNAPSHOT_TASK,\n  SET_SNAPSHOT_TASK,\n  CLEAR_SNAPSHOT_TASK,\n  NODE_EVENTS_INSTALLED,\n} = require(\"./constants\");\n\nconst LOCAL_STORAGE_METHODS = [\"setItem\", \"getItem\", \"removeItem\", \"clear\"];\n\nfunction logDisabled(method) {\n  return function () {\n    this._cy.log(`localStorage.${method} is disabled`);\n  };\n}\n\nfunction logDisabledMethodName(localStorageMethod) {\n  return `_log${localStorageMethod}Disabled`;\n}\n\nclass LocalStorage {\n  static get cypressCommands() {\n    return [\n      \"clearLocalStorageSnapshot\",\n      \"saveLocalStorage\",\n      \"restoreLocalStorage\",\n      \"setLocalStorage\",\n      \"getLocalStorage\",\n      \"removeLocalStorage\",\n      \"disableLocalStorage\",\n    ];\n  }\n\n  constructor(localStorage, cy, Cypress) {\n    this._nodeEventsInstalled =\n      (typeof Cypress.expose === \"function\"\n        ? Cypress.expose(NODE_EVENTS_INSTALLED)\n        : Cypress.env(NODE_EVENTS_INSTALLED)) === true;\n    this._snapshot = {};\n    this._namedSnapshots = {};\n    this._cy = cy;\n    this._localStorage = localStorage;\n\n    LOCAL_STORAGE_METHODS.forEach((localStorageMethod) => {\n      this[logDisabledMethodName(localStorageMethod)] =\n        logDisabled(localStorageMethod).bind(this);\n    });\n  }\n\n  _saveLocalStorageKeyToMemory(key, snapshotName) {\n    if (snapshotName) {\n      this._namedSnapshots[snapshotName][key] = this._localStorage.getItem(key);\n    } else {\n      this._snapshot[key] = this._localStorage.getItem(key);\n    }\n  }\n\n  _saveLocalStorageToMemory(snapshotName) {\n    Object.keys(this._localStorage).forEach((key) => {\n      this._saveLocalStorageKeyToMemory(key, snapshotName);\n    });\n  }\n\n  _clearMemorySnapshot(snapshotName) {\n    if (snapshotName) {\n      this._namedSnapshots[snapshotName] = {};\n    } else {\n      this._snapshot = {};\n    }\n  }\n\n  _getSnapshotFromMemory(snapshotName) {\n    return snapshotName ? this._namedSnapshots[snapshotName] : this._snapshot;\n  }\n\n  _restoreLocalStorageFromSnapshot(obj = {}) {\n    Object.keys(obj).forEach((key) => {\n      this._localStorage.setItem(key, obj[key]);\n    });\n  }\n\n  _restoreLocalStorageFromMemory(snapshotName) {\n    this._restoreLocalStorageFromSnapshot(\n      this._getSnapshotFromMemory(snapshotName),\n    );\n  }\n\n  _copySnapshotFromMemoryToNode(snapshotName) {\n    if (this._nodeEventsInstalled) {\n      return this._cy.task(SET_SNAPSHOT_TASK, {\n        name: snapshotName,\n        snapshot: this._getSnapshotFromMemory(snapshotName),\n      });\n    }\n  }\n\n  _clearNodeSnapshot(snapshotName) {\n    if (this._nodeEventsInstalled) {\n      return this._cy.task(CLEAR_SNAPSHOT_TASK, snapshotName);\n    }\n  }\n\n  _restoreLocalStorageFromNode(snapshotName) {\n    return this._cy.task(GET_SNAPSHOT_TASK, snapshotName).then((snapshot) => {\n      this._restoreLocalStorageFromSnapshot(snapshot);\n    });\n  }\n\n  clearLocalStorageSnapshot(snapshotName) {\n    this._clearMemorySnapshot(snapshotName);\n    return this._clearNodeSnapshot(snapshotName);\n  }\n\n  saveLocalStorage(snapshotName) {\n    if (!this._localStorage.getItem.wrappedMethod) {\n      this.clearLocalStorageSnapshot(snapshotName);\n      this._saveLocalStorageToMemory(snapshotName);\n      return this._copySnapshotFromMemoryToNode(snapshotName);\n    }\n  }\n\n  restoreLocalStorage(snapshotName) {\n    this._localStorage.clear();\n    if (this._nodeEventsInstalled) {\n      return this._restoreLocalStorageFromNode(snapshotName);\n    } else {\n      this._restoreLocalStorageFromMemory(snapshotName);\n    }\n  }\n\n  getLocalStorage(key) {\n    return this._localStorage.getItem(key);\n  }\n\n  setLocalStorage(key, value) {\n    return this._localStorage.setItem(key, value);\n  }\n\n  removeLocalStorage(key) {\n    return this._localStorage.removeItem(key);\n  }\n\n  disableLocalStorage(options = {}) {\n    this._cy.on(\"window:before:load\", (win) => {\n      if (\n        win.localStorage &&\n        !win.localStorage[LOCAL_STORAGE_METHODS[0]].wrappedMethod &&\n        !this._localStorage[LOCAL_STORAGE_METHODS[0]].wrappedMethod\n      ) {\n        LOCAL_STORAGE_METHODS.forEach((localStorageMethod) => {\n          this._cy\n            .stub(this._localStorage, localStorageMethod)\n            .callsFake(this[logDisabledMethodName(localStorageMethod)]);\n          this._cy\n            .stub(win.localStorage, localStorageMethod)\n            .throws(options.withError);\n        });\n      }\n    });\n  }\n}\n\nmodule.exports = LocalStorage;\n"
  },
  {
    "path": "src/constants.js",
    "content": "const GET_SNAPSHOT_TASK = \"cypressLocalStorageGetSnapshot\";\nconst SET_SNAPSHOT_TASK = \"cypressLocalStorageSetSnapshot\";\nconst CLEAR_SNAPSHOT_TASK = \"cypressLocalStorageClearSnapshot\";\nconst NODE_EVENTS_INSTALLED = \"LOCALSTORAGE_NODE_EVENTS_INSTALLED\";\n\nmodule.exports = {\n  GET_SNAPSHOT_TASK,\n  SET_SNAPSHOT_TASK,\n  CLEAR_SNAPSHOT_TASK,\n  NODE_EVENTS_INSTALLED,\n};\n"
  },
  {
    "path": "src/plugin.js",
    "content": "const {\n  GET_SNAPSHOT_TASK,\n  SET_SNAPSHOT_TASK,\n  CLEAR_SNAPSHOT_TASK,\n  NODE_EVENTS_INSTALLED,\n} = require(\"./constants\");\n\nconst plugin = (on, config) => {\n  const namedSnapshots = {};\n  let globalSnapshot = {};\n\n  if (config.expose === undefined) {\n    config.env[NODE_EVENTS_INSTALLED] = true;\n  } else {\n    config.expose[NODE_EVENTS_INSTALLED] = true;\n  }\n\n  // Create cypress-local-storage-commands tasks\n  on(\"task\", {\n    [GET_SNAPSHOT_TASK]: function (name) {\n      return name ? namedSnapshots[name] || {} : globalSnapshot;\n    },\n    [SET_SNAPSHOT_TASK]: function ({ name, snapshot }) {\n      if (name) {\n        namedSnapshots[name] = snapshot;\n      } else {\n        globalSnapshot = snapshot;\n      }\n      return null;\n    },\n    [CLEAR_SNAPSHOT_TASK]: function (name) {\n      if (name) {\n        namedSnapshots[name] = {};\n      } else {\n        globalSnapshot = {};\n      }\n      return null;\n    },\n  });\n\n  return config;\n};\n\nmodule.exports = plugin;\n"
  },
  {
    "path": "src/register.js",
    "content": "const LocalStorage = require(\"./LocalStorage\");\n\nconst register = (Cypress, cy, localStorage) => {\n  const localStorageCommands = new LocalStorage(localStorage, cy, Cypress);\n\n  // Register commands\n  LocalStorage.cypressCommands.forEach((commandName) => {\n    Cypress.Commands.add(\n      commandName,\n      localStorageCommands[commandName].bind(localStorageCommands),\n    );\n  });\n};\n\nmodule.exports = {\n  register,\n};\n"
  },
  {
    "path": "stryker.conf.js",
    "content": "const BRANCH_NAME = process.env.BRANCH_NAME;\nconst STRYKER_DASHBOARD_API_KEY = process.env.STRYKER_DASHBOARD_API_KEY;\n\nconst BASE_CONFIG = {\n  ignorePatterns: [\"**\", \"!*.js\", \"!src/**/*.js\", \"!test/**/*.js\"],\n  packageManager: \"npm\",\n  thresholds: {\n    high: 80,\n    low: 60,\n    break: 80,\n  },\n  reporters: [\"html\", \"clear-text\", \"progress\", \"dashboard\"],\n  testRunner: \"jest\",\n  coverageAnalysis: \"off\",\n  plugins: [\"@stryker-mutator/jest-runner\"],\n};\n\nconst config = {\n  ...BASE_CONFIG,\n  dashboard:\n    BRANCH_NAME && STRYKER_DASHBOARD_API_KEY\n      ? {\n          project: \"github.com/javierbrea/cypress-localstorage-commands\",\n          version: BRANCH_NAME,\n        }\n      : undefined,\n};\n\nmodule.exports = config;\n"
  },
  {
    "path": "test/Cy.mock.js",
    "content": "const sinon = require(\"sinon\");\n\nconst doNothing = () => {\n  // do nothing\n};\n\nclass Cy {\n  constructor() {\n    this._sandbox = sinon.createSandbox();\n\n    this._windowMock = {\n      localStorage: {\n        setItem: doNothing,\n        getItem: doNothing,\n        removeItem: doNothing,\n        clear: doNothing,\n      },\n    };\n\n    this._stubs = {\n      on: this._sandbox.stub().callsFake((_eventName, callback) => {\n        this._callback = callback;\n      }),\n      log: this._sandbox.stub(),\n      stub: this._sandbox.stub,\n      task: this._sandbox.stub().resolves(),\n    };\n  }\n\n  get stubs() {\n    return this._stubs;\n  }\n\n  restore() {\n    this._sandbox.restore();\n  }\n\n  reset() {\n    this._sandbox.reset();\n  }\n\n  loadWindow() {\n    this._callback(this._windowMock);\n  }\n\n  get window() {\n    return this._windowMock;\n  }\n}\n\nmodule.exports = Cy;\n"
  },
  {
    "path": "test/Cypress.mock.js",
    "content": "const sinon = require(\"sinon\");\n\nconst Mock = class Mock {\n  constructor() {\n    this._sandbox = sinon.createSandbox();\n\n    this._stubs = {\n      Commands: {\n        add: this._sandbox.stub(),\n      },\n      env: this._sandbox.stub(),\n      expose: this._sandbox.stub(),\n    };\n  }\n\n  get stubs() {\n    return this._stubs;\n  }\n\n  restore() {\n    this._sandbox.restore();\n  }\n};\n\nmodule.exports = Mock;\n"
  },
  {
    "path": "test/LocalStorage.mock.js",
    "content": "const sinon = require(\"sinon\");\n\nconst LOCALSTORAGE_METHODS = new Set([\n  \"getItem\",\n  \"setItem\",\n  \"removeItem\",\n  \"clear\",\n]);\n\nconst Mock = class Mock {\n  constructor() {\n    this._sandbox = sinon.createSandbox();\n\n    this._stubs = {\n      getItem: this._sandbox.stub().callsFake((key) => {\n        return this._stubs[key];\n      }),\n      setItem: this._sandbox.stub().callsFake((key, value) => {\n        if (!LOCALSTORAGE_METHODS.has(key)) {\n          this._stubs[key] = value;\n        }\n      }),\n      removeItem: this._sandbox.stub().callsFake((key) => {\n        delete this._stubs[key];\n      }),\n      clear: this._sandbox.stub().callsFake(() => {\n        Object.keys(this._stubs).forEach((key) => {\n          if (!LOCALSTORAGE_METHODS.has(key)) {\n            delete this._stubs[key];\n          }\n        });\n      }),\n    };\n  }\n\n  get stubs() {\n    return this._stubs;\n  }\n\n  restore() {\n    this._sandbox.restore();\n  }\n\n  reset() {\n    this._sandbox.reset();\n  }\n};\n\nmodule.exports = Mock;\n"
  },
  {
    "path": "test/LocalStorage.spec.js",
    "content": "const LocalStorageMock = require(\"./LocalStorage.mock\");\nconst CyMock = require(\"./Cy.mock\");\nconst CypressMock = require(\"./Cypress.mock\");\nconst LocalStorage = require(\"../src/LocalStorage\");\n\ndescribe(\"LocalStorage\", () => {\n  let windowLocalStorageMock;\n  let localStorageMock;\n  let localStorage;\n  let cyMock;\n  let cypressMock;\n\n  beforeAll(() => {\n    cyMock = new CyMock();\n    // Ensure that tasks are not called (plugin must be disabled in these tests)\n    cyMock.stubs.task.throws();\n    cypressMock = new CypressMock();\n    localStorageMock = new LocalStorageMock();\n    localStorage = new LocalStorage(\n      localStorageMock.stubs,\n      cyMock.stubs,\n      cypressMock.stubs,\n    );\n  });\n\n  afterAll(() => {\n    cyMock.restore();\n    localStorageMock.restore();\n  });\n\n  describe(\"LocalStorage\", () => {\n    describe(\"save and restore methods\", () => {\n      it(\"should restore values that localStorage had when save method was called\", () => {\n        expect.assertions(2);\n        localStorageMock.stubs.setItem(\"foo\", \"foo-value\");\n        localStorageMock.stubs.setItem(\"var\", \"var-value\");\n        localStorage.saveLocalStorage();\n        localStorageMock.stubs.setItem(\"foo\", \"foo-new-value\");\n        expect(localStorageMock.stubs.getItem(\"foo\")).toEqual(\"foo-new-value\");\n        localStorage.restoreLocalStorage();\n        expect(localStorageMock.stubs.getItem(\"foo\")).toEqual(\"foo-value\");\n      });\n\n      it(\"should restore values after calling localStorage clear\", () => {\n        expect.assertions(2);\n        localStorageMock.stubs.clear();\n        expect(localStorageMock.stubs.getItem(\"var\")).toEqual(undefined);\n        localStorage.restoreLocalStorage();\n        expect(localStorageMock.stubs.getItem(\"var\")).toEqual(\"var-value\");\n      });\n\n      it(\"should restore new values if Save is called again\", () => {\n        expect.assertions(2);\n        localStorageMock.stubs.setItem(\"foo\", \"foo-new-value\");\n        localStorageMock.stubs.removeItem(\"var\");\n        localStorage.saveLocalStorage();\n        localStorageMock.stubs.setItem(\"foo\", \"foo-another-new-value\");\n        localStorageMock.stubs.setItem(\"var\", \"foo-var-value\");\n        localStorage.restoreLocalStorage();\n        expect(localStorageMock.stubs.getItem(\"foo\")).toEqual(\"foo-new-value\");\n        expect(localStorageMock.stubs.getItem(\"var\")).toEqual(undefined);\n      });\n    });\n\n    describe(\"Clear method\", () => {\n      it(\"should clear values in localStorage snapshot, but maintain localStorage values\", () => {\n        expect.assertions(4);\n        localStorageMock.stubs.setItem(\"var\", \"foo-var-value\");\n        localStorage.clearLocalStorageSnapshot();\n        expect(localStorageMock.stubs.getItem(\"foo\")).toEqual(\"foo-new-value\");\n        expect(localStorageMock.stubs.getItem(\"var\")).toEqual(\"foo-var-value\");\n        localStorage.restoreLocalStorage();\n        expect(localStorageMock.stubs.getItem(\"foo\")).toEqual(undefined);\n        expect(localStorageMock.stubs.getItem(\"var\")).toEqual(undefined);\n      });\n    });\n  });\n\n  describe(\"LocalStorage named snapshots\", () => {\n    describe(\"save and restore methods\", () => {\n      it(\"should restore values that localStorage had when save method was called\", () => {\n        expect.assertions(3);\n        localStorageMock.stubs.setItem(\"foo\", \"foo-value\");\n        localStorageMock.stubs.setItem(\"var\", \"var-value\");\n        localStorage.saveLocalStorage(\"first\");\n        localStorageMock.stubs.setItem(\"foo\", \"foo-new-value\");\n        localStorage.saveLocalStorage(\"second\");\n        expect(localStorageMock.stubs.getItem(\"foo\")).toEqual(\"foo-new-value\");\n        localStorage.restoreLocalStorage(\"first\");\n        expect(localStorageMock.stubs.getItem(\"foo\")).toEqual(\"foo-value\");\n        localStorage.restoreLocalStorage(\"second\");\n        expect(localStorageMock.stubs.getItem(\"foo\")).toEqual(\"foo-new-value\");\n      });\n\n      it(\"should clear whole localStorage if snapshot to restore does not exists\", () => {\n        localStorage.restoreLocalStorage(\"fourth\");\n        expect(localStorageMock.stubs.getItem(\"foo\")).toEqual(undefined);\n        expect(localStorageMock.stubs.getItem(\"var\")).toEqual(undefined);\n      });\n    });\n\n    describe(\"Clear method\", () => {\n      it(\"should clear values in localStorage snapshot, but maintain localStorage values\", () => {\n        expect.assertions(4);\n        localStorage.restoreLocalStorage(\"second\");\n        localStorageMock.stubs.setItem(\"var\", \"foo-var-value\");\n        localStorage.clearLocalStorageSnapshot(\"second\");\n        expect(localStorageMock.stubs.getItem(\"foo\")).toEqual(\"foo-new-value\");\n        expect(localStorageMock.stubs.getItem(\"var\")).toEqual(\"foo-var-value\");\n        localStorage.restoreLocalStorage(\"second\");\n        expect(localStorageMock.stubs.getItem(\"foo\")).toEqual(undefined);\n        expect(localStorageMock.stubs.getItem(\"var\")).toEqual(undefined);\n      });\n\n      it(\"should not clear values from other snapshot\", () => {\n        localStorage.restoreLocalStorage(\"first\");\n        expect(localStorageMock.stubs.getItem(\"foo\")).toEqual(\"foo-value\");\n        expect(localStorageMock.stubs.getItem(\"var\")).toEqual(\"var-value\");\n      });\n    });\n  });\n\n  describe(\"setLocalStorage method\", () => {\n    it(\"should set values in localStorage\", () => {\n      expect.assertions(2);\n      localStorage.setLocalStorage(\"foo\", \"foo-value\");\n      localStorage.setLocalStorage(\"var\", \"var-value\");\n      expect(localStorageMock.stubs.getItem(\"foo\")).toEqual(\"foo-value\");\n      expect(localStorageMock.stubs.getItem(\"var\")).toEqual(\"var-value\");\n    });\n\n    it(\"should not have set values in localStorage snapshot\", () => {\n      expect.assertions(2);\n      localStorage.restoreLocalStorage();\n      expect(localStorageMock.stubs.getItem(\"foo\")).toEqual(undefined);\n      expect(localStorageMock.stubs.getItem(\"var\")).toEqual(undefined);\n    });\n  });\n\n  describe(\"getLocalStorage method\", () => {\n    it(\"should get localStorage items\", () => {\n      expect.assertions(2);\n      localStorage.setLocalStorage(\"foo\", \"foo-value\");\n      localStorage.setLocalStorage(\"var\", \"var-value\");\n      expect(localStorage.getLocalStorage(\"foo\")).toEqual(\"foo-value\");\n      expect(localStorage.getLocalStorage(\"var\")).toEqual(\"var-value\");\n    });\n  });\n\n  describe(\"removeLocalStorage\", () => {\n    it(\"should remove local storage items\", () => {\n      expect.assertions(2);\n      localStorage.saveLocalStorage();\n      localStorage.removeLocalStorage(\"foo\");\n      expect(localStorage.getLocalStorage(\"foo\")).toEqual(undefined);\n      expect(localStorage.getLocalStorage(\"var\")).toEqual(\"var-value\");\n    });\n\n    it(\"should not remove local storage items from localstorage snapshot\", () => {\n      expect.assertions(2);\n      localStorage.restoreLocalStorage();\n      expect(localStorage.getLocalStorage(\"foo\")).toEqual(\"foo-value\");\n      expect(localStorage.getLocalStorage(\"var\")).toEqual(\"var-value\");\n    });\n  });\n\n  describe(\"LocalStorage when memory is cleaned\", () => {\n    describe(\"save and restore methods\", () => {\n      it(\"should not restore values that localStorage had when save method was called\", () => {\n        expect.assertions(2);\n        localStorageMock.stubs.setItem(\"foo\", \"foo-value\");\n        localStorageMock.stubs.setItem(\"var\", \"var-value\");\n        localStorage.saveLocalStorage();\n        localStorageMock.stubs.setItem(\"foo\", \"foo-new-value\");\n        expect(localStorageMock.stubs.getItem(\"foo\")).toEqual(\"foo-new-value\");\n        localStorage._namedSnapshots = {};\n        localStorage._snapshot = {};\n        localStorage.restoreLocalStorage();\n        expect(localStorageMock.stubs.getItem(\"foo\")).toEqual(undefined);\n      });\n\n      it(\"should not restore values after calling localStorage clear\", () => {\n        expect.assertions(2);\n        localStorageMock.stubs.clear();\n        expect(localStorageMock.stubs.getItem(\"var\")).toEqual(undefined);\n        localStorage.restoreLocalStorage();\n        expect(localStorageMock.stubs.getItem(\"var\")).toEqual(undefined);\n      });\n\n      it(\"should not restore new values if Save is called again\", () => {\n        expect.assertions(2);\n        localStorageMock.stubs.setItem(\"foo\", \"foo-new-value\");\n        localStorageMock.stubs.removeItem(\"var\");\n        localStorage.saveLocalStorage();\n        localStorageMock.stubs.setItem(\"foo\", \"foo-another-new-value\");\n        localStorageMock.stubs.setItem(\"var\", \"foo-var-value\");\n        localStorage._namedSnapshots = {};\n        localStorage._snapshot = {};\n        localStorage.restoreLocalStorage();\n        expect(localStorageMock.stubs.getItem(\"foo\")).toEqual(undefined);\n        expect(localStorageMock.stubs.getItem(\"var\")).toEqual(undefined);\n      });\n    });\n  });\n\n  describe(\"disableLocalStorage\", () => {\n    beforeEach(() => {\n      windowLocalStorageMock = new CyMock();\n      cyMock = new CyMock();\n      cypressMock = new CypressMock();\n      localStorage = new LocalStorage(\n        windowLocalStorageMock.window.localStorage,\n        cyMock.stubs,\n        cypressMock.stubs,\n      );\n    });\n\n    afterEach(() => {\n      windowLocalStorageMock.restore();\n    });\n\n    it(\"should do nothing if page is not reloaded\", () => {\n      expect.assertions(3);\n      localStorage.disableLocalStorage();\n      expect(() => cyMock.window.localStorage.setItem()).not.toThrow();\n      expect(() => cyMock.window.localStorage.getItem()).not.toThrow();\n      expect(() => cyMock.window.localStorage.removeItem()).not.toThrow();\n    });\n\n    it(\"should use Cypress window:before:load event to create stubs\", () => {\n      localStorage.disableLocalStorage();\n      expect(cyMock.stubs.on.getCall(0).args[0]).toEqual(\"window:before:load\");\n    });\n\n    it(\"should make localStorage methods to throw after reloading page\", () => {\n      expect.assertions(3);\n      localStorage.disableLocalStorage();\n      cyMock.loadWindow();\n      expect(() => cyMock.window.localStorage.setItem()).toThrow();\n      expect(() => cyMock.window.localStorage.getItem()).toThrow();\n      expect(() => cyMock.window.localStorage.removeItem()).toThrow();\n    });\n\n    it(\"should make cy.setLocalStorage command to log after reloading page\", () => {\n      expect.assertions(1);\n      localStorage.disableLocalStorage();\n      cyMock.loadWindow();\n      localStorage.setLocalStorage(\"foo\", \"foo\");\n      expect(\n        cyMock.stubs.log.calledWith(\"localStorage.setItem is disabled\"),\n      ).toEqual(true);\n    });\n\n    it(\"should make cy.getLocalStorage command to log after reloading page\", () => {\n      expect.assertions(1);\n      localStorage.disableLocalStorage();\n      cyMock.loadWindow();\n      localStorage.getLocalStorage(\"foo\");\n      expect(\n        cyMock.stubs.log.calledWith(\"localStorage.getItem is disabled\"),\n      ).toEqual(true);\n    });\n\n    it(\"should make cy.removeLocalStorage command to log after reloading page\", () => {\n      expect.assertions(1);\n      localStorage.disableLocalStorage();\n      cyMock.loadWindow();\n      localStorage.removeLocalStorage(\"foo\");\n      expect(\n        cyMock.stubs.log.calledWith(\"localStorage.removeItem is disabled\"),\n      ).toEqual(true);\n    });\n\n    it(\"should make cy.restoreLocalStorage command to log after reloading page\", () => {\n      expect.assertions(1);\n      localStorage.disableLocalStorage();\n      cyMock.loadWindow();\n      localStorage.restoreLocalStorage();\n      expect(\n        cyMock.stubs.log.calledWith(\"localStorage.clear is disabled\"),\n      ).toEqual(true);\n    });\n\n    it(\"should make cy.saveLocalStorage command to do nothing\", () => {\n      expect.assertions(1);\n      localStorage.disableLocalStorage();\n      cyMock.loadWindow();\n      localStorage.saveLocalStorage();\n      expect(\n        windowLocalStorageMock.window.localStorage.getItem.callCount,\n      ).toEqual(0);\n    });\n\n    it(\"should do nothing if window.localStorage is not available\", () => {\n      cyMock.window.localStorage = null;\n      localStorage.disableLocalStorage();\n      cyMock.loadWindow();\n      localStorage.setLocalStorage(\"foo\", \"foo\");\n      expect(cyMock.stubs.log.callCount).toEqual(0);\n    });\n\n    it(\"should work when reloading page multiple times\", () => {\n      expect.assertions(3);\n      localStorage.disableLocalStorage();\n      cyMock.loadWindow();\n      cyMock.loadWindow();\n      cyMock.loadWindow();\n      expect(() => cyMock.window.localStorage.setItem()).toThrow();\n      expect(() => cyMock.window.localStorage.getItem()).toThrow();\n      expect(() => cyMock.window.localStorage.removeItem()).toThrow();\n    });\n\n    it(\"should work when called multiple times\", () => {\n      expect.assertions(3);\n      localStorage.disableLocalStorage();\n      cyMock.loadWindow();\n      localStorage.disableLocalStorage();\n      localStorage.disableLocalStorage();\n      cyMock.loadWindow();\n      expect(() => cyMock.window.localStorage.setItem()).toThrow();\n      expect(() => cyMock.window.localStorage.getItem()).toThrow();\n      expect(() => cyMock.window.localStorage.removeItem()).toThrow();\n    });\n\n    it(\"should throw error provided in the 'withError' option\", () => {\n      expect.assertions(3);\n      const error = new Error(\"foo\");\n      localStorage.disableLocalStorage({\n        withError: error,\n      });\n      cyMock.loadWindow();\n      expect(() => cyMock.window.localStorage.setItem()).toThrow(error);\n      expect(() => cyMock.window.localStorage.getItem()).toThrow(error);\n      expect(() => cyMock.window.localStorage.removeItem()).toThrow(error);\n    });\n  });\n});\n"
  },
  {
    "path": "test/LocalStorageNode.spec.js",
    "content": "const LocalStorageMock = require(\"./LocalStorage.mock\");\nconst CyMock = require(\"./Cy.mock\");\nconst CypressMock = require(\"./Cypress.mock\");\nconst LocalStorage = require(\"../src/LocalStorage\");\nconst plugin = require(\"../src/plugin\");\n\ndescribe(\"LocalStorage with node events\", () => {\n  let localStorageMock;\n  let localStorage;\n  let cyMock;\n  let cypressMock;\n  let cypressTasks;\n  let config;\n\n  const setupTest = (useExpose) => {\n    cyMock = new CyMock();\n    cypressMock = new CypressMock();\n    config = useExpose ? { expose: {} } : { env: {} };\n\n    cypressTasks = {};\n\n    plugin((cyEvent, tasks) => {\n      if (cyEvent === \"task\") {\n        Object.keys(tasks).forEach((taskName) => {\n          cypressTasks[taskName] = tasks[taskName];\n        });\n      }\n    }, config);\n\n    cyMock.stubs.task.callsFake((taskName, arg) => {\n      if (!taskName) {\n        throw new Error(\"Task name is required\");\n      }\n      return new Promise((resolve, reject) => {\n        const result = cypressTasks[taskName](arg);\n        if (result === undefined) {\n          reject(new Error(\"Task did not return a value\"));\n        }\n        resolve(result);\n      });\n    });\n\n    if (useExpose) {\n      cypressMock.stubs.expose.callsFake((envVarName) => {\n        if (!envVarName) {\n          throw new Error(\"Env var name is required\");\n        }\n        return config.expose[envVarName];\n      });\n    } else {\n      cypressMock.stubs.env.callsFake((envVarName) => {\n        if (!envVarName) {\n          throw new Error(\"Env var name is required\");\n        }\n        return config.env[envVarName];\n      });\n      // Mock expose to be undefined to simulate older Cypress versions\n      cypressMock.stubs.expose = undefined;\n    }\n\n    localStorageMock = new LocalStorageMock();\n    localStorage = new LocalStorage(\n      localStorageMock.stubs,\n      cyMock.stubs,\n      cypressMock.stubs,\n    );\n  };\n\n  afterEach(() => {\n    cyMock.restore();\n    localStorageMock.restore();\n  });\n\n  describe(\"when using Cypress.env (Cypress < 15.10.0)\", () => {\n    beforeEach(() => {\n      setupTest(false);\n    });\n\n    it(\"should configure and read node events status correctly\", () => {\n      expect(config.env.LOCALSTORAGE_NODE_EVENTS_INSTALLED).toEqual(true);\n      expect(localStorage._nodeEventsInstalled).toEqual(true);\n    });\n  });\n\n  describe(\"when using Cypress.expose (Cypress >= 15.10.0)\", () => {\n    beforeEach(() => {\n      setupTest(true);\n    });\n\n    it(\"should configure and read node events status correctly\", () => {\n      expect(config.expose.LOCALSTORAGE_NODE_EVENTS_INSTALLED).toEqual(true);\n      expect(localStorage._nodeEventsInstalled).toEqual(true);\n    });\n  });\n\n  describe(\"LocalStorage\", () => {\n    beforeEach(() => {\n      setupTest(false); // Can use either for standard testing\n      // clear memory to ensure that plugin is working\n      localStorage._namedSnapshots = {};\n      localStorage._snapshot = {};\n    });\n\n    describe(\"save and restore methods\", () => {\n      it(\"should restore values that localStorage had when save method was called\", async () => {\n        expect.assertions(2);\n        localStorageMock.stubs.setItem(\"foo\", \"foo-value\");\n        localStorageMock.stubs.setItem(\"var\", \"var-value\");\n        await localStorage.saveLocalStorage();\n        localStorageMock.stubs.setItem(\"foo\", \"foo-new-value\");\n        expect(localStorageMock.stubs.getItem(\"foo\")).toEqual(\"foo-new-value\");\n        await localStorage.restoreLocalStorage();\n        expect(localStorageMock.stubs.getItem(\"foo\")).toEqual(\"foo-value\");\n      });\n\n      it(\"should restore values from node snapshot when memory snapshot is empty\", async () => {\n        expect.assertions(1);\n        localStorageMock.stubs.setItem(\"foo\", \"foo-value\");\n        await localStorage.saveLocalStorage();\n        localStorageMock.stubs.clear();\n        localStorage._snapshot = {};\n        localStorage._namedSnapshots = {};\n        await localStorage.restoreLocalStorage();\n        expect(localStorageMock.stubs.getItem(\"foo\")).toEqual(\"foo-value\");\n      });\n\n      it(\"should restore values after calling localStorage clear\", async () => {\n        expect.assertions(2);\n        localStorageMock.stubs.setItem(\"var\", \"var-value\");\n        await localStorage.saveLocalStorage();\n        localStorageMock.stubs.clear();\n        expect(localStorageMock.stubs.getItem(\"var\")).toEqual(undefined);\n        await localStorage.restoreLocalStorage();\n        expect(localStorageMock.stubs.getItem(\"var\")).toEqual(\"var-value\");\n      });\n\n      it(\"should restore new values if Save is called again\", async () => {\n        expect.assertions(2);\n        localStorageMock.stubs.setItem(\"foo\", \"foo-new-value\");\n        localStorageMock.stubs.removeItem(\"var\");\n        await localStorage.saveLocalStorage();\n        localStorageMock.stubs.setItem(\"foo\", \"foo-another-new-value\");\n        localStorageMock.stubs.setItem(\"var\", \"foo-var-value\");\n        await localStorage.restoreLocalStorage();\n        expect(localStorageMock.stubs.getItem(\"foo\")).toEqual(\"foo-new-value\");\n        expect(localStorageMock.stubs.getItem(\"var\")).toEqual(undefined);\n      });\n    });\n\n    describe(\"Clear method\", () => {\n      it(\"should clear values in localStorage snapshot, but maintain localStorage values\", async () => {\n        expect.assertions(4);\n        localStorageMock.stubs.setItem(\"foo\", \"foo-new-value\");\n        localStorageMock.stubs.setItem(\"var\", \"foo-var-value\");\n        await localStorage.saveLocalStorage();\n        await localStorage.clearLocalStorageSnapshot();\n        expect(localStorageMock.stubs.getItem(\"foo\")).toEqual(\"foo-new-value\");\n        expect(localStorageMock.stubs.getItem(\"var\")).toEqual(\"foo-var-value\");\n        await localStorage.restoreLocalStorage();\n        expect(localStorageMock.stubs.getItem(\"foo\")).toEqual(undefined);\n        expect(localStorageMock.stubs.getItem(\"var\")).toEqual(undefined);\n      });\n    });\n  });\n\n  describe(\"LocalStorage named snapshots\", () => {\n    beforeEach(() => {\n      setupTest(false);\n      localStorage._namedSnapshots = {};\n      localStorage._snapshot = {};\n    });\n    describe(\"save and restore methods\", () => {\n      it(\"should restore values that localStorage had when save method was called\", async () => {\n        expect.assertions(3);\n        localStorageMock.stubs.setItem(\"foo\", \"foo-value\");\n        localStorageMock.stubs.setItem(\"var\", \"var-value\");\n        await localStorage.saveLocalStorage(\"first\");\n        localStorageMock.stubs.setItem(\"foo\", \"foo-new-value\");\n        await localStorage.saveLocalStorage(\"second\");\n        expect(localStorageMock.stubs.getItem(\"foo\")).toEqual(\"foo-new-value\");\n        await localStorage.restoreLocalStorage(\"first\");\n        expect(localStorageMock.stubs.getItem(\"foo\")).toEqual(\"foo-value\");\n        await localStorage.restoreLocalStorage(\"second\");\n        expect(localStorageMock.stubs.getItem(\"foo\")).toEqual(\"foo-new-value\");\n      });\n\n      it(\"should clear whole localStorage if snapshot to restore does not exists\", async () => {\n        await localStorage.restoreLocalStorage(\"fourth\");\n        expect(localStorageMock.stubs.getItem(\"foo\")).toEqual(undefined);\n        expect(localStorageMock.stubs.getItem(\"var\")).toEqual(undefined);\n      });\n    });\n\n    describe(\"Clear method\", () => {\n      it(\"should clear values in localStorage snapshot, but maintain localStorage values\", async () => {\n        expect.assertions(4);\n        localStorageMock.stubs.setItem(\"foo\", \"foo-new-value\");\n        localStorageMock.stubs.setItem(\"var\", \"foo-var-value\");\n        await localStorage.saveLocalStorage(\"second\");\n        await localStorage.restoreLocalStorage(\"second\");\n        localStorageMock.stubs.setItem(\"var\", \"foo-var-value\");\n        await localStorage.clearLocalStorageSnapshot(\"second\");\n        expect(localStorageMock.stubs.getItem(\"foo\")).toEqual(\"foo-new-value\");\n        expect(localStorageMock.stubs.getItem(\"var\")).toEqual(\"foo-var-value\");\n        await localStorage.restoreLocalStorage(\"second\");\n        expect(localStorageMock.stubs.getItem(\"foo\")).toEqual(undefined);\n        expect(localStorageMock.stubs.getItem(\"var\")).toEqual(undefined);\n      });\n\n      it(\"should not clear values from other snapshot\", async () => {\n        localStorageMock.stubs.setItem(\"foo\", \"foo-value\");\n        localStorageMock.stubs.setItem(\"var\", \"var-value\");\n        await localStorage.saveLocalStorage(\"first\");\n        await localStorage.restoreLocalStorage(\"first\");\n        expect(localStorageMock.stubs.getItem(\"foo\")).toEqual(\"foo-value\");\n        expect(localStorageMock.stubs.getItem(\"var\")).toEqual(\"var-value\");\n      });\n    });\n  });\n\n  describe(\"setLocalStorage method\", () => {\n    beforeEach(() => {\n      setupTest(false);\n      localStorage._namedSnapshots = {};\n      localStorage._snapshot = {};\n    });\n    it(\"should set values in localStorage\", async () => {\n      expect.assertions(2);\n      await localStorage.setLocalStorage(\"foo\", \"foo-value\");\n      await localStorage.setLocalStorage(\"var\", \"var-value\");\n      expect(localStorageMock.stubs.getItem(\"foo\")).toEqual(\"foo-value\");\n      expect(localStorageMock.stubs.getItem(\"var\")).toEqual(\"var-value\");\n    });\n\n    it(\"should not have set values in localStorage snapshot\", async () => {\n      expect.assertions(2);\n      await localStorage.restoreLocalStorage();\n      expect(localStorageMock.stubs.getItem(\"foo\")).toEqual(undefined);\n      expect(localStorageMock.stubs.getItem(\"var\")).toEqual(undefined);\n    });\n  });\n});\n"
  },
  {
    "path": "test/register.spec.js",
    "content": "const LocalStorageMock = require(\"./LocalStorage.mock\");\nconst CypressMock = require(\"./Cypress.mock\");\n\nconst LocalStorage = require(\"../src/LocalStorage\");\nconst { register } = require(\"../src/register\");\n\ndescribe(\"register\", () => {\n  let cypressMock;\n  let localStorageMock;\n\n  beforeEach(() => {\n    localStorageMock = new LocalStorageMock();\n    cypressMock = new CypressMock();\n    register(cypressMock.stubs, localStorageMock.stubs);\n  });\n\n  afterEach(() => {\n    localStorageMock.restore();\n    cypressMock.restore();\n  });\n\n  describe(\"methods\", () => {\n    it(\"should register all LocalStorage public methods as commands on Cypress\", () => {\n      expect(cypressMock.stubs.Commands.add.callCount).toEqual(\n        LocalStorage.cypressCommands.length,\n      );\n    });\n\n    it(\"should register clearLocalStorageSnapshot method\", () => {\n      expect(\n        cypressMock.stubs.Commands.add.calledWith(\"clearLocalStorageSnapshot\"),\n      ).toBe(true);\n    });\n\n    it(\"should register saveLocalStorage method\", () => {\n      expect(\n        cypressMock.stubs.Commands.add.calledWith(\"saveLocalStorage\"),\n      ).toBe(true);\n    });\n\n    it(\"should register restoreLocalStorage method\", () => {\n      expect(\n        cypressMock.stubs.Commands.add.calledWith(\"restoreLocalStorage\"),\n      ).toBe(true);\n    });\n  });\n});\n"
  },
  {
    "path": "test-e2e/app/.gitignore",
    "content": "# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n#environment variables\n#.env\n\n# dependencies\n/node_modules\n\n#build\n/build\n\n# misc\n.DS_Store\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# ides\n.idea\n.vs\n\n# caches\n.eslintcache\n"
  },
  {
    "path": "test-e2e/app/package.json",
    "content": "{\n  \"name\": \"app\",\n  \"private\": true,\n  \"dependencies\": {\n    \"@data-provider/browser-storage\": \"4.0.0\",\n    \"@data-provider/core\": \"4.0.0\",\n    \"@data-provider/react\": \"2.0.0\",\n    \"prop-types\": \"15.8.1\",\n    \"react\": \"18.3.1\",\n    \"react-dom\": \"18.3.1\",\n    \"react-redux\": \"8.1.3\",\n    \"redux\": \"4.2.1\"\n  },\n  \"scripts\": {\n    \"start\": \"DISABLE_ESLINT_PLUGIN=true react-scripts start\",\n    \"build\": \"DISABLE_ESLINT_PLUGIN=true react-scripts build\",\n    \"serve\": \"serve -l 3000 --no-request-logging\",\n    \"build:serve\": \"pnpm run build && pnpm run serve\"\n  },\n  \"browserslist\": {\n    \"production\": [\n      \">0.2%\",\n      \"not dead\",\n      \"not op_mini all\"\n    ],\n    \"development\": [\n      \"last 1 chrome version\",\n      \"last 1 firefox version\",\n      \"last 1 safari version\"\n    ]\n  },\n  \"devDependencies\": {\n    \"react-scripts\": \"5.0.1\",\n    \"serve\": \"14.2.6\"\n  }\n}\n"
  },
  {
    "path": "test-e2e/app/public/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n    <meta name=\"theme-color\" content=\"#000000\" />\n    <meta\n      name=\"description\"\n      content=\"user preferences mock app\"\n    />\n    <title>React App</title>\n  </head>\n  <body>\n    <noscript>You need to enable JavaScript to run this app.</noscript>\n    <div id=\"root\"></div>\n  </body>\n</html>\n"
  },
  {
    "path": "test-e2e/app/serve.json",
    "content": "{\n  \"public\": \"build\",\n  \"trailingSlash\": false,\n  \"directoryListing\": false,\n  \"cleanUrls\": true,\n  \"rewrites\": [\n    {\n      \"source\": \"/\",\n      \"destination\": \"/index.html\"\n    }\n  ]\n}\n"
  },
  {
    "path": "test-e2e/app/src/App.css",
    "content": ".App {\n  text-align: center;\n}\n\n.App-header {\n  background-color: #282c34;\n  min-height: 100vh;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  justify-content: center;\n  font-size: calc(10px + 2vmin);\n  color: white;\n}\n"
  },
  {
    "path": "test-e2e/app/src/App.js",
    "content": "import { Provider } from \"react-redux\";\nimport { createStore, combineReducers } from \"redux\";\nimport { storeManager } from \"@data-provider/core\";\nimport \"./App.css\";\nimport AcceptCookies from \"./modules/accept-cookies\";\nimport RejectCookies from \"./modules/reject-cookies\";\nimport CookiesValue from \"./modules/cookies-value\";\nimport LocalStorageWarning from \"./modules/localstorage-warning\";\n\nconst store = createStore(\n  combineReducers({\n    dataProviders: storeManager.reducer,\n  }),\n  globalThis?.__REDUX_DEVTOOLS_EXTENSION__?.(),\n);\n\nstoreManager.setStore(store, \"dataProviders\");\n\nfunction App() {\n  return (\n    <Provider store={store}>\n      <div className=\"App\">\n        <header className=\"App-header\">\n          <p>\n            Click cookies button and reload the page to see how value is\n            maintained\n          </p>\n          <AcceptCookies />\n          <RejectCookies />\n          <CookiesValue />\n          <LocalStorageWarning />\n        </header>\n      </div>\n    </Provider>\n  );\n}\n\nexport default App;\n"
  },
  {
    "path": "test-e2e/app/src/components/cookies-button/CookiesButton.css",
    "content": "button.cookies-button {\n  color: #09d3ac;\n  padding: 10px;\n  font-size: 20px;\n  border: 1px solid #09d3ac;\n  background-color: #282828;\n  cursor:pointer;\n}\n\nbutton.cookies-button:hover {\n  color: #09d3a0;\n  background-color: #222;\n}\n\nbutton.cookies-button:disabled, button.cookies-button:disabled:hover  {\n  opacity: 0.3;\n  color: #09d3ac;\n  background-color: #282828;\n  cursor:default;\n}\n"
  },
  {
    "path": "test-e2e/app/src/components/cookies-button/CookiesButton.js",
    "content": "import PropTypes from \"prop-types\";\n\nimport \"./CookiesButton.css\";\n\nexport const CookiesButton = ({ visible, onClick, id, text, disabled }) => {\n  if (!visible) {\n    return null;\n  }\n  return (\n    <button\n      onClick={onClick}\n      id={id}\n      className=\"cookies-button\"\n      disabled={disabled}\n    >\n      {text}\n    </button>\n  );\n};\n\nCookiesButton.propTypes = {\n  visible: PropTypes.bool,\n  onClick: PropTypes.func,\n  id: PropTypes.string,\n  text: PropTypes.string,\n  disabled: PropTypes.bool,\n};\n"
  },
  {
    "path": "test-e2e/app/src/components/cookies-button/index.js",
    "content": "export { CookiesButton as default } from \"./CookiesButton\";\n"
  },
  {
    "path": "test-e2e/app/src/components/cookies-value/CookiesValue.js",
    "content": "import PropTypes from \"prop-types\";\n\nexport const CookiesValue = ({ value }) => {\n  return (\n    <p>\n      Cookies are currently{\" \"}\n      <span id=\"cookies-value\">{value ? \"accepted\" : \"rejected\"}</span>\n    </p>\n  );\n};\n\nCookiesValue.propTypes = {\n  value: PropTypes.bool,\n};\n"
  },
  {
    "path": "test-e2e/app/src/components/cookies-value/index.js",
    "content": "export { CookiesValue as default } from \"./CookiesValue\";\n"
  },
  {
    "path": "test-e2e/app/src/data/user-preferences/actions.js",
    "content": "import { userPreferences } from \"./origins\";\n\nfunction log(...args) {\n  // eslint-disable-next-line no-console\n  console.log(...args);\n}\n\nexport const acceptCookies = () => {\n  // save value directly in another localStorage key for an easier assertions example\n  try {\n    localStorage.setItem(\"cookies-accepted\", true);\n  } catch (err) {\n    log(\"Error setting cookies-accepted\", err);\n  }\n\n  return userPreferences.queries\n    .cookiesAccepted()\n    .update(true)\n    .catch((err) => {\n      log(\"Error setting user-preferences\", err);\n    });\n};\n\nexport const rejectCookies = () => {\n  // save value directly in another localStorage key for an easier assertions example\n  try {\n    localStorage.setItem(\"cookies-accepted\", false);\n  } catch (err) {\n    log(\"Error setting cookies-accepted\", err);\n  }\n  return userPreferences.queries\n    .cookiesAccepted()\n    .update(false)\n    .catch((err) => {\n      log(\"Error setting user-preferences\", err);\n    });\n};\n"
  },
  {
    "path": "test-e2e/app/src/data/user-preferences/index.js",
    "content": "export * from \"./origins\";\nexport * from \"./selectors\";\nexport * from \"./actions\";\n"
  },
  {
    "path": "test-e2e/app/src/data/user-preferences/origins.js",
    "content": "import { LocalStorage } from \"@data-provider/browser-storage\";\n\nexport const userPreferences = new LocalStorage({\n  id: \"user-preferences\",\n  storageFallback: false,\n});\n\nuserPreferences.addQuery(\"cookiesAccepted\", () => ({\n  prop: \"cookiesAccepted\",\n}));\n"
  },
  {
    "path": "test-e2e/app/src/data/user-preferences/selectors.js",
    "content": "import { Selector } from \"@data-provider/core\";\n\nimport { userPreferences } from \"./origins\";\n\nexport const cookiesAccepted = new Selector(\n  userPreferences.queries.cookiesAccepted(),\n  {\n    id: \"cookies-accepted\",\n  },\n);\n"
  },
  {
    "path": "test-e2e/app/src/index.css",
    "content": "body {\n  margin: 0;\n  font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Roboto\", \"Oxygen\",\n    \"Ubuntu\", \"Cantarell\", \"Fira Sans\", \"Droid Sans\", \"Helvetica Neue\",\n    sans-serif;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n"
  },
  {
    "path": "test-e2e/app/src/index.js",
    "content": "import ReactDOM from \"react-dom\";\nimport \"./index.css\";\nimport App from \"./App\";\n\nReactDOM.render(<App />, document.getElementById(\"root\"));\n"
  },
  {
    "path": "test-e2e/app/src/modules/accept-cookies/AcceptCookies.js",
    "content": "import { useData, useError } from \"@data-provider/react\";\n\nimport CookiesButton from \"../../components/cookies-button\";\nimport { cookiesAccepted, acceptCookies } from \"../../data/user-preferences\";\n\nconst AcceptCookies = () => {\n  const accepted = useData(cookiesAccepted);\n  const error = useError(cookiesAccepted);\n  return (\n    <CookiesButton\n      visible={!accepted}\n      text=\"Accept cookies\"\n      id=\"accept-cookies\"\n      onClick={acceptCookies}\n      disabled={!!error}\n    />\n  );\n};\n\nexport default AcceptCookies;\n"
  },
  {
    "path": "test-e2e/app/src/modules/accept-cookies/index.js",
    "content": "export { default } from \"./AcceptCookies\";\n"
  },
  {
    "path": "test-e2e/app/src/modules/cookies-value/CookiesValue.js",
    "content": "import { withData } from \"@data-provider/react\";\n\nimport CookiesValue from \"../../components/cookies-value\";\nimport { cookiesAccepted } from \"../../data/user-preferences\";\n\nexport default withData(cookiesAccepted, \"value\")(CookiesValue);\n"
  },
  {
    "path": "test-e2e/app/src/modules/cookies-value/index.js",
    "content": "export { default } from \"./CookiesValue\";\n"
  },
  {
    "path": "test-e2e/app/src/modules/localstorage-warning/LocalStorageWarning.css",
    "content": "#localstorage-disabled-warning {\n  color: #ff9900;\n}\n"
  },
  {
    "path": "test-e2e/app/src/modules/localstorage-warning/LocalStorageWarning.js",
    "content": "import { useError } from \"@data-provider/react\";\n\nimport { cookiesAccepted } from \"../../data/user-preferences\";\n\nimport \"./LocalStorageWarning.css\";\n\nconst LocalStorageWarning = () => {\n  const error = useError(cookiesAccepted);\n\n  if (!error) {\n    return null;\n  }\n\n  return (\n    <p id=\"localstorage-disabled-warning\">\n      ⚠️ LocalStorage is disabled. Received error:{\" \"}\n      <span id=\"localstorage-error\">{error.message}</span>\n    </p>\n  );\n};\n\nexport default LocalStorageWarning;\n"
  },
  {
    "path": "test-e2e/app/src/modules/localstorage-warning/index.js",
    "content": "export { default } from \"./LocalStorageWarning\";\n"
  },
  {
    "path": "test-e2e/app/src/modules/reject-cookies/RejectCookies.js",
    "content": "import { useData } from \"@data-provider/react\";\n\nimport CookiesButton from \"../../components/cookies-button\";\nimport { cookiesAccepted, rejectCookies } from \"../../data/user-preferences\";\n\nconst RejectCookies = () => {\n  const visible = useData(cookiesAccepted);\n  return (\n    <CookiesButton\n      text=\"Reject cookies\"\n      id=\"reject-cookies\"\n      onClick={rejectCookies}\n      visible={visible}\n    />\n  );\n};\n\nexport default RejectCookies;\n"
  },
  {
    "path": "test-e2e/app/src/modules/reject-cookies/index.js",
    "content": "export { default } from \"./RejectCookies\";\n"
  },
  {
    "path": "test-e2e/cypress-14/.gitignore",
    "content": "# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n#environment variables\n#.env\n\n# dependencies\n/node_modules\n\n# tests\n/cypress/screenshots\n/cypress/fixtures\n/cypress/videos\n\n# misc\n.DS_Store\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# ides\n.idea\n.vs\n\n# caches\n.eslintcache\n"
  },
  {
    "path": "test-e2e/cypress-14/babel.config.js",
    "content": "module.exports = {\n  plugins: [\n    [\n      \"module-resolver\",\n      {\n        root: [\".\"],\n        alias: {\n          \"cypress-localstorage-commands\": `../../`,\n        },\n      },\n    ],\n  ],\n};\n"
  },
  {
    "path": "test-e2e/cypress-14/cypress/plugins/index.js",
    "content": "/// <reference types=\"cypress\" />\n// ***********************************************************\n// This example plugins/index.js can be used to load plugins\n//\n// You can change the location of this file or turn off loading\n// the plugins file with the 'pluginsFile' configuration option.\n//\n// You can read more here:\n// https://on.cypress.io/plugins-guide\n// ***********************************************************\n\n// This function is called when a project is opened or re-opened (e.g. due to\n// the project's config changing)\n\n/**\n * @type {Cypress.PluginConfig}\n */\n// eslint-disable-next-line no-unused-vars\nconst createConfig = (_on, _config) => {\n  // `on` is used to hook into various events Cypress emits\n  // `config` is the resolved Cypress config\n};\n\nmodule.exports = createConfig;\n"
  },
  {
    "path": "test-e2e/cypress-14/cypress/support/commands.js",
    "content": "// eslint-disable-next-line import/no-unresolved\nimport \"cypress-localstorage-commands\";\n"
  },
  {
    "path": "test-e2e/cypress-14/cypress/support/e2e.js",
    "content": "import \"./commands\";\n"
  },
  {
    "path": "test-e2e/cypress-14/cypress.config.js",
    "content": "const webpackPreprocessor = require(\"@cypress/webpack-preprocessor\");\nconst defaults = webpackPreprocessor.defaultOptions;\n\nmodule.exports = {\n  e2e: {\n    baseUrl: \"http://localhost:3000\",\n    setupNodeEvents(on, config) {\n      require(\"../../src/plugin\")(on, config);\n      delete defaults.webpackOptions.module.rules[0].use[0].options.presets;\n      on(\"file:preprocessor\", webpackPreprocessor(defaults));\n      return config;\n    },\n    specPattern: [\n      \"../specs/cypress/e2e/*.cy.js\",\n      \"../specs/cypress/e2e/across-specs/save.cy.js\",\n      \"../specs/cypress/e2e/across-specs/restore.cy.js\",\n      \"../specs/cypress/e2e/named-across-specs/save.cy.js\",\n      \"../specs/cypress/e2e/named-across-specs/restore.cy.js\",\n      \"../specs/cypress/e2e/named-across-specs/restore-after-clear.cy.js\",\n    ],\n  },\n  video: false,\n};\n"
  },
  {
    "path": "test-e2e/cypress-14/package.json",
    "content": "{\n  \"name\": \"cypress-14\",\n  \"private\": true,\n  \"scripts\": {\n    \"build:serve\": \"cd ../app && pnpm run build:serve\",\n    \"cypress:install\": \"cypress install\",\n    \"cypress:verify\": \"cypress verify\",\n    \"cypress:open\": \"cypress open\",\n    \"cypress:run\": \"cypress run\",\n    \"test:ci\": \"start-server-and-test build:serve http-get://localhost:3000 cypress:run\"\n  },\n  \"devDependencies\": {\n    \"cypress\": \"14.5.3\"\n  }\n}\n"
  },
  {
    "path": "test-e2e/cypress-14-no-plugin/.gitignore",
    "content": "# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n#environment variables\n#.env\n\n# dependencies\n/node_modules\n\n# tests\n/cypress/screenshots\n/cypress/fixtures\n/cypress/videos\n\n# misc\n.DS_Store\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# ides\n.idea\n.vs\n\n# caches\n.eslintcache\n"
  },
  {
    "path": "test-e2e/cypress-14-no-plugin/babel.config.js",
    "content": "module.exports = {\n  plugins: [\n    [\n      \"module-resolver\",\n      {\n        root: [\".\"],\n        alias: {\n          \"cypress-localstorage-commands\": `../../`,\n        },\n      },\n    ],\n  ],\n};\n"
  },
  {
    "path": "test-e2e/cypress-14-no-plugin/cypress/plugins/index.js",
    "content": "/// <reference types=\"cypress\" />\n// ***********************************************************\n// This example plugins/index.js can be used to load plugins\n//\n// You can change the location of this file or turn off loading\n// the plugins file with the 'pluginsFile' configuration option.\n//\n// You can read more here:\n// https://on.cypress.io/plugins-guide\n// ***********************************************************\n\n// This function is called when a project is opened or re-opened (e.g. due to\n// the project's config changing)\n\n/**\n * @type {Cypress.PluginConfig}\n */\n// eslint-disable-next-line no-unused-vars\nconst createConfig = (_on, _config) => {\n  // `on` is used to hook into various events Cypress emits\n  // `config` is the resolved Cypress config\n};\n\nmodule.exports = createConfig;\n"
  },
  {
    "path": "test-e2e/cypress-14-no-plugin/cypress/support/commands.js",
    "content": "// eslint-disable-next-line import/no-unresolved\nimport \"cypress-localstorage-commands\";\n"
  },
  {
    "path": "test-e2e/cypress-14-no-plugin/cypress/support/e2e.js",
    "content": "import \"./commands\";\n"
  },
  {
    "path": "test-e2e/cypress-14-no-plugin/cypress.config.js",
    "content": "const webpackPreprocessor = require(\"@cypress/webpack-preprocessor\");\nconst defaults = webpackPreprocessor.defaultOptions;\n\nmodule.exports = {\n  e2e: {\n    baseUrl: \"http://localhost:3000\",\n    setupNodeEvents(on) {\n      delete defaults.webpackOptions.module.rules[0].use[0].options.presets;\n      on(\"file:preprocessor\", webpackPreprocessor(defaults));\n    },\n    specPattern: [\n      \"../specs/cypress/e2e/*.cy.js\",\n      \"../specs/cypress/e2e/no-across-specs/save.cy.js\",\n      \"../specs/cypress/e2e/no-across-specs/restore.cy.js\",\n    ],\n  },\n  video: false,\n};\n"
  },
  {
    "path": "test-e2e/cypress-14-no-plugin/package.json",
    "content": "{\n  \"name\": \"cypress-14-no-plugin\",\n  \"private\": true,\n  \"scripts\": {\n    \"build:serve\": \"cd ../app && pnpm run build:serve\",\n    \"cypress:install\": \"cypress install\",\n    \"cypress:verify\": \"cypress verify\",\n    \"cypress:open\": \"cypress open\",\n    \"cypress:run\": \"cypress run\",\n    \"test:ci\": \"start-server-and-test build:serve http-get://localhost:3000 cypress:run\"\n  },\n  \"devDependencies\": {\n    \"cypress\": \"14.5.3\"\n  }\n}\n"
  },
  {
    "path": "test-e2e/cypress-9/.gitignore",
    "content": "# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n#environment variables\n#.env\n\n# dependencies\n/node_modules\n\n# tests\n/cypress/screenshots\n/cypress/fixtures\n/cypress/videos\n/cypress/integration\n\n# misc\n.DS_Store\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# ides\n.idea\n.vs\n\n# caches\n.eslintcache\n"
  },
  {
    "path": "test-e2e/cypress-9/babel.config.js",
    "content": "module.exports = {\n  plugins: [\n    [\n      \"module-resolver\",\n      {\n        root: [\".\"],\n        alias: {\n          \"cypress-localstorage-commands\": `../../`,\n        },\n      },\n    ],\n  ],\n};\n"
  },
  {
    "path": "test-e2e/cypress-9/cypress/.eslintrc.json",
    "content": "{\n  \"env\": {\n    \"node\": true,\n    \"es6\": true\n  },\n  \"globals\": {\n    \"cy\": true,\n    \"afterEach\": true,\n    \"after\": true,\n    \"before\": true,\n    \"beforeEach\": true,\n    \"describe\": true,\n    \"expect\": true,\n    \"it\": true\n  }\n}\n"
  },
  {
    "path": "test-e2e/cypress-9/cypress/plugins/index.js",
    "content": "const webpackPreprocessor = require(\"@cypress/webpack-preprocessor\");\nconst defaults = webpackPreprocessor.defaultOptions;\n\nconst plugin = require(\"../../../../plugin\");\n\nconst registerPlugins = (on, config) => {\n  plugin(on, config);\n  delete defaults.webpackOptions.module.rules[0].use[0].options.presets;\n  on(\"file:preprocessor\", webpackPreprocessor(defaults));\n  return config;\n};\n\nmodule.exports = registerPlugins;\n"
  },
  {
    "path": "test-e2e/cypress-9/cypress/support/commands.js",
    "content": "// eslint-disable-next-line import/no-unresolved\nimport \"cypress-localstorage-commands\";\n"
  },
  {
    "path": "test-e2e/cypress-9/cypress/support/index.js",
    "content": "import \"./commands\";\n"
  },
  {
    "path": "test-e2e/cypress-9/cypress.config.js",
    "content": "module.exports = {\n  baseUrl: \"http://localhost:3000\",\n  video: false,\n  testFiles: [\n    \"*.cy.js\",\n    \"across-specs/save.cy.js\",\n    \"across-specs/restore.cy.js\",\n    \"named-across-specs/save.cy.js\",\n    \"named-across-specs/restore.cy.js\",\n    \"named-across-specs/restore-after-clear.cy.js\",\n  ],\n};\n"
  },
  {
    "path": "test-e2e/cypress-9/package.json",
    "content": "{\n  \"name\": \"cypress-9\",\n  \"private\": true,\n  \"scripts\": {\n    \"build:serve\": \"cd ../app && pnpm run build:serve\",\n    \"cypress:install\": \"cypress install\",\n    \"cypress:verify\": \"cypress verify\",\n    \"cypress:open\": \"cypress open\",\n    \"cypress:run\": \"cypress run\",\n    \"copy:specs\": \"node scripts/copySpecs.js\",\n    \"build-and-serve-and-cypress\": \"start-server-and-test build:serve http-get://localhost:3000 cypress:run\",\n    \"test:ci\": \"pnpm run copy:specs && pnpm run build-and-serve-and-cypress\"\n  },\n  \"devDependencies\": {\n    \"cypress\": \"9.7.0\"\n  }\n}\n"
  },
  {
    "path": "test-e2e/cypress-9/scripts/copySpecs.js",
    "content": "const path = require(\"node:path\");\nconst fsExtra = require(\"fs-extra\");\n\nconst rootPath = path.resolve(__dirname, \"..\");\nconst destPath = path.resolve(rootPath, \"cypress\", \"integration\");\nconst specsPath = path.resolve(rootPath, \"..\", \"specs\", \"cypress\", \"e2e\");\n\nconst copyLib = () => {\n  fsExtra.removeSync(destPath);\n  fsExtra.copySync(specsPath, destPath);\n};\n\ncopyLib();\n"
  },
  {
    "path": "test-e2e/cypress-9-no-plugin/.gitignore",
    "content": "# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n#environment variables\n#.env\n\n# dependencies\n/node_modules\n\n# tests\n/cypress/screenshots\n/cypress/fixtures\n/cypress/videos\n/cypress/integration\n\n# misc\n.DS_Store\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# ides\n.idea\n.vs\n\n# caches\n.eslintcache\n"
  },
  {
    "path": "test-e2e/cypress-9-no-plugin/babel.config.js",
    "content": "module.exports = {\n  plugins: [\n    [\n      \"module-resolver\",\n      {\n        root: [\".\"],\n        alias: {\n          \"cypress-localstorage-commands\": `../../`,\n        },\n      },\n    ],\n  ],\n};\n"
  },
  {
    "path": "test-e2e/cypress-9-no-plugin/cypress/.eslintrc.json",
    "content": "{\n  \"env\": {\n    \"node\": true,\n    \"es6\": true\n  },\n  \"globals\": {\n    \"cy\": true,\n    \"afterEach\": true,\n    \"after\": true,\n    \"before\": true,\n    \"beforeEach\": true,\n    \"describe\": true,\n    \"expect\": true,\n    \"it\": true\n  }\n}\n"
  },
  {
    "path": "test-e2e/cypress-9-no-plugin/cypress/plugins/index.js",
    "content": "const webpackPreprocessor = require(\"@cypress/webpack-preprocessor\");\nconst defaults = webpackPreprocessor.defaultOptions;\n\nconst registerPlugins = (on, config) => {\n  delete defaults.webpackOptions.module.rules[0].use[0].options.presets;\n  on(\"file:preprocessor\", webpackPreprocessor(defaults));\n  return config;\n};\n\nmodule.exports = registerPlugins;\n"
  },
  {
    "path": "test-e2e/cypress-9-no-plugin/cypress/support/commands.js",
    "content": "// eslint-disable-next-line import/no-unresolved\nimport \"cypress-localstorage-commands\";\n"
  },
  {
    "path": "test-e2e/cypress-9-no-plugin/cypress/support/index.js",
    "content": "import \"./commands\";\n"
  },
  {
    "path": "test-e2e/cypress-9-no-plugin/cypress.config.js",
    "content": "module.exports = {\n  baseUrl: \"http://localhost:3000\",\n  video: false,\n  testFiles: [\n    \"*.cy.js\",\n    \"no-across-specs/save.cy.js\",\n    \"no-across-specs/restore.cy.js\",\n  ],\n};\n"
  },
  {
    "path": "test-e2e/cypress-9-no-plugin/package.json",
    "content": "{\n  \"name\": \"cypress-9-no-plugin\",\n  \"private\": true,\n  \"scripts\": {\n    \"build:serve\": \"cd ../app && pnpm run build:serve\",\n    \"cypress:install\": \"cypress install\",\n    \"cypress:verify\": \"cypress verify\",\n    \"cypress:open\": \"cypress open\",\n    \"cypress:run\": \"cypress run\",\n    \"copy:specs\": \"node scripts/copySpecs.js\",\n    \"build-and-serve-and-cypress\": \"start-server-and-test build:serve http-get://localhost:3000 cypress:run\",\n    \"test:ci\": \"pnpm run copy:specs && pnpm run build-and-serve-and-cypress\"\n  },\n  \"devDependencies\": {\n    \"cypress\": \"9.7.0\"\n  }\n}\n"
  },
  {
    "path": "test-e2e/cypress-9-no-plugin/scripts/copySpecs.js",
    "content": "const path = require(\"node:path\");\nconst fsExtra = require(\"fs-extra\");\n\nconst rootPath = path.resolve(__dirname, \"..\");\nconst destPath = path.resolve(rootPath, \"cypress\", \"integration\");\nconst specsPath = path.resolve(rootPath, \"..\", \"specs\", \"cypress\", \"e2e\");\n\nconst copyLib = () => {\n  fsExtra.removeSync(destPath);\n  fsExtra.copySync(specsPath, destPath);\n};\n\ncopyLib();\n"
  },
  {
    "path": "test-e2e/cypress-latest/.gitignore",
    "content": "# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n#environment variables\n#.env\n\n# dependencies\n/node_modules\n\n# tests\n/cypress/screenshots\n/cypress/fixtures\n/cypress/videos\n\n# misc\n.DS_Store\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# ides\n.idea\n.vs\n\n# caches\n.eslintcache\n"
  },
  {
    "path": "test-e2e/cypress-latest/babel.config.js",
    "content": "module.exports = {\n  plugins: [\n    [\n      \"module-resolver\",\n      {\n        root: [\".\"],\n        alias: {\n          \"cypress-localstorage-commands\": `../../`,\n        },\n      },\n    ],\n  ],\n};\n"
  },
  {
    "path": "test-e2e/cypress-latest/cypress/plugins/index.js",
    "content": "/// <reference types=\"cypress\" />\n// ***********************************************************\n// This example plugins/index.js can be used to load plugins\n//\n// You can change the location of this file or turn off loading\n// the plugins file with the 'pluginsFile' configuration option.\n//\n// You can read more here:\n// https://on.cypress.io/plugins-guide\n// ***********************************************************\n\n// This function is called when a project is opened or re-opened (e.g. due to\n// the project's config changing)\n\n/**\n * @type {Cypress.PluginConfig}\n */\n// eslint-disable-next-line no-unused-vars\nconst createConfig = (_on, _config) => {\n  // `on` is used to hook into various events Cypress emits\n  // `config` is the resolved Cypress config\n};\n\nmodule.exports = createConfig;\n"
  },
  {
    "path": "test-e2e/cypress-latest/cypress/support/commands.js",
    "content": "// eslint-disable-next-line import/no-unresolved\nimport \"cypress-localstorage-commands\";\n"
  },
  {
    "path": "test-e2e/cypress-latest/cypress/support/e2e.js",
    "content": "import \"./commands\";\n"
  },
  {
    "path": "test-e2e/cypress-latest/cypress.config.js",
    "content": "const webpackPreprocessor = require(\"@cypress/webpack-preprocessor\");\nconst defaults = webpackPreprocessor.defaultOptions;\n\nmodule.exports = {\n  e2e: {\n    baseUrl: \"http://localhost:3000\",\n    setupNodeEvents(on, config) {\n      require(\"../../src/plugin\")(on, config);\n      delete defaults.webpackOptions.module.rules[0].use[0].options.presets;\n      on(\"file:preprocessor\", webpackPreprocessor(defaults));\n      return config;\n    },\n    specPattern: [\n      \"../specs/cypress/e2e/*.cy.js\",\n      \"../specs/cypress/e2e/across-specs/save.cy.js\",\n      \"../specs/cypress/e2e/across-specs/restore.cy.js\",\n      \"../specs/cypress/e2e/named-across-specs/save.cy.js\",\n      \"../specs/cypress/e2e/named-across-specs/restore.cy.js\",\n      \"../specs/cypress/e2e/named-across-specs/restore-after-clear.cy.js\",\n    ],\n  },\n  video: false,\n  allowCypressEnv: false,\n};\n"
  },
  {
    "path": "test-e2e/cypress-latest/package.json",
    "content": "{\n  \"name\": \"cypress-latest\",\n  \"private\": true,\n  \"scripts\": {\n    \"build:serve\": \"cd ../app && pnpm run build:serve\",\n    \"cypress:install\": \"cypress install\",\n    \"cypress:verify\": \"cypress verify\",\n    \"cypress:open\": \"cypress open\",\n    \"cypress:run\": \"cypress run\",\n    \"test:ci\": \"start-server-and-test build:serve http-get://localhost:3000 cypress:run\"\n  },\n  \"devDependencies\": {\n    \"cypress\": \"15.10.0\"\n  }\n}\n"
  },
  {
    "path": "test-e2e/cypress-latest-no-plugin/.gitignore",
    "content": "# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n#environment variables\n#.env\n\n# dependencies\n/node_modules\n\n# tests\n/cypress/screenshots\n/cypress/fixtures\n/cypress/videos\n\n# misc\n.DS_Store\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# ides\n.idea\n.vs\n\n# caches\n.eslintcache\n"
  },
  {
    "path": "test-e2e/cypress-latest-no-plugin/babel.config.js",
    "content": "module.exports = {\n  plugins: [\n    [\n      \"module-resolver\",\n      {\n        root: [\".\"],\n        alias: {\n          \"cypress-localstorage-commands\": `../../`,\n        },\n      },\n    ],\n  ],\n};\n"
  },
  {
    "path": "test-e2e/cypress-latest-no-plugin/cypress/plugins/index.js",
    "content": "/// <reference types=\"cypress\" />\n// ***********************************************************\n// This example plugins/index.js can be used to load plugins\n//\n// You can change the location of this file or turn off loading\n// the plugins file with the 'pluginsFile' configuration option.\n//\n// You can read more here:\n// https://on.cypress.io/plugins-guide\n// ***********************************************************\n\n// This function is called when a project is opened or re-opened (e.g. due to\n// the project's config changing)\n\n/**\n * @type {Cypress.PluginConfig}\n */\n// eslint-disable-next-line no-unused-vars\nconst createConfig = (_on, _config) => {\n  // `on` is used to hook into various events Cypress emits\n  // `config` is the resolved Cypress config\n};\n\nmodule.exports = createConfig;\n"
  },
  {
    "path": "test-e2e/cypress-latest-no-plugin/cypress/support/commands.js",
    "content": "// eslint-disable-next-line import/no-unresolved\nimport \"cypress-localstorage-commands\";\n"
  },
  {
    "path": "test-e2e/cypress-latest-no-plugin/cypress/support/e2e.js",
    "content": "import \"./commands\";\n"
  },
  {
    "path": "test-e2e/cypress-latest-no-plugin/cypress.config.js",
    "content": "const webpackPreprocessor = require(\"@cypress/webpack-preprocessor\");\nconst defaults = webpackPreprocessor.defaultOptions;\n\nmodule.exports = {\n  e2e: {\n    baseUrl: \"http://localhost:3000\",\n    setupNodeEvents(on) {\n      delete defaults.webpackOptions.module.rules[0].use[0].options.presets;\n      on(\"file:preprocessor\", webpackPreprocessor(defaults));\n    },\n    specPattern: [\n      \"../specs/cypress/e2e/*.cy.js\",\n      \"../specs/cypress/e2e/no-across-specs/save.cy.js\",\n      \"../specs/cypress/e2e/no-across-specs/restore.cy.js\",\n    ],\n  },\n  video: false,\n  allowCypressEnv: false,\n};\n"
  },
  {
    "path": "test-e2e/cypress-latest-no-plugin/package.json",
    "content": "{\n  \"name\": \"cypress-latest-no-plugin\",\n  \"private\": true,\n  \"scripts\": {\n    \"build:serve\": \"cd ../app && pnpm run build:serve\",\n    \"cypress:install\": \"cypress install\",\n    \"cypress:verify\": \"cypress verify\",\n    \"cypress:open\": \"cypress open\",\n    \"cypress:run\": \"cypress run\",\n    \"test:ci\": \"start-server-and-test build:serve http-get://localhost:3000 cypress:run\"\n  },\n  \"devDependencies\": {\n    \"cypress\": \"15.10.0\"\n  }\n}\n"
  },
  {
    "path": "test-e2e/cypress-typescript/.eslintignore",
    "content": "/node_modules"
  },
  {
    "path": "test-e2e/cypress-typescript/.gitignore",
    "content": "# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n#environment variables\n#.env\n\n# dependencies\n/node_modules\n\n#build\n/build\n\n# tests\n/cypress/screenshots\n/cypress/fixtures\n\n# misc\n.DS_Store\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# ides\n.idea\n.vs\n\n# Generated files\n/cypress/support/cypress-localstorage-commands\n\n# caches\n.eslintcache\n"
  },
  {
    "path": "test-e2e/cypress-typescript/cypress/e2e/assertions-example.cy.ts",
    "content": "// Next reference is commented as package is not available at node_modules\n//// <reference types=\"cypress-localstorage-commands\" />\n\ndescribe(\"localStorage cookies-accepted item\", () => {\n  beforeEach(() => {\n    cy.restoreLocalStorage();\n    cy.visit(\"/\");\n  });\n\n  afterEach(() => {\n    cy.saveLocalStorage();\n  });\n\n  it(\"should be null first time page is visited\", () => {\n    cy.getLocalStorage(\"cookies-accepted\").should(\"equal\", null);\n  });\n\n  it(\"should be true after clicking cookies button\", () => {\n    cy.get(\"#accept-cookies\").click();\n    cy.getLocalStorage(\"cookies-accepted\").should(\"equal\", \"true\");\n  });\n\n  it(\"should be true after reloading\", () => {\n    cy.getLocalStorage(\"cookies-accepted\").then((cookiesAccepted) => {\n      if (cookiesAccepted !== null) {\n        expect(JSON.parse(cookiesAccepted)).to.equal(true);\n      }\n      expect(cookiesAccepted).to.equal(\"true\");\n    });\n  });\n});\n"
  },
  {
    "path": "test-e2e/cypress-typescript/cypress/e2e/cookies-example.cy.ts",
    "content": "// Next reference is commented as package is not available at node_modules\n//// <reference types=\"cypress-localstorage-commands\" />\n\ndescribe(\"Accept cookies button\", () => {\n  const COOKIES_BUTTON = \"#accept-cookies\";\n  const LOCALSTORAGE_DISABLED_WARNING = \"#localstorage-disabled-warning\";\n  const LOCALSTORAGE_ERROR = \"#localstorage-error\";\n\n  before(() => {\n    cy.clearLocalStorageSnapshot();\n  });\n\n  beforeEach(() => {\n    cy.restoreLocalStorage();\n    cy.visit(\"/\");\n  });\n\n  afterEach(() => {\n    cy.saveLocalStorage();\n  });\n\n  it(\"should be visible\", () => {\n    cy.get(COOKIES_BUTTON).should(\"be.visible\");\n  });\n\n  it(\"should not be visible after clicked\", () => {\n    cy.get(COOKIES_BUTTON).click();\n    cy.get(COOKIES_BUTTON).should(\"not.exist\");\n  });\n\n  it(\"should still be visible when reloading if localStorage is disabled\", () => {\n    cy.disableLocalStorage();\n    cy.reload();\n    cy.get(COOKIES_BUTTON).should(\"be.visible\");\n  });\n\n  it(\"should display warning if localStorage is disabled\", () => {\n    cy.disableLocalStorage();\n    cy.reload();\n    cy.get(LOCALSTORAGE_DISABLED_WARNING).should(\"be.visible\");\n  });\n\n  it(\"should display localStorage error message\", () => {\n    cy.disableLocalStorage();\n    cy.reload();\n    cy.get(LOCALSTORAGE_ERROR).should(\"have.text\", \"Error\");\n  });\n\n  it(\"should not be visible after reloading\", () => {\n    cy.get(COOKIES_BUTTON).should(\"not.exist\");\n  });\n});\n"
  },
  {
    "path": "test-e2e/cypress-typescript/cypress/e2e/cookies.cy.ts",
    "content": "// Next reference is commented as package is not available at node_modules\n//// <reference types=\"cypress-localstorage-commands\" />\n\ndescribe(\"Cookies\", () => {\n  const SELECTORS = {\n    ACCEPT_BUTTON: \"#accept-cookies\",\n    REJECT_BUTTON: \"#reject-cookies\",\n    LOCALSTORAGE_DISABLED_WARNING: \"#localstorage-disabled-warning\",\n  };\n\n  beforeEach(() => {\n    cy.visit(\"/\");\n  });\n\n  describe(\"when cookies are not accepted\", () => {\n    it(\"should display accept cookies button\", () => {\n      cy.get(SELECTORS.ACCEPT_BUTTON).should(\"be.visible\");\n    });\n  });\n\n  describe(\"when user click accept cookies button\", () => {\n    describe(\"without using localStorage commands\", () => {\n      it(\"should display reject cookies button\", () => {\n        cy.get(SELECTORS.ACCEPT_BUTTON).click();\n        cy.get(SELECTORS.REJECT_BUTTON).should(\"be.visible\");\n      });\n\n      it(\"should accept cookies button after reloading page\", () => {\n        cy.reload();\n        cy.getLocalStorage(\"cookies-accepted\").should(\"not.exist\");\n        cy.get(SELECTORS.ACCEPT_BUTTON).should(\"be.visible\");\n      });\n    });\n\n    describe(\"saving and restoring local storage\", () => {\n      it(\"should display reject cookies button\", () => {\n        cy.getLocalStorage(\"cookies-accepted\").should(\"not.exist\");\n        cy.get(SELECTORS.ACCEPT_BUTTON).click();\n        cy.getLocalStorage(\"cookies-accepted\").should(\"equal\", \"true\");\n        cy.get(SELECTORS.REJECT_BUTTON).should(\"be.visible\");\n        cy.saveLocalStorage();\n      });\n\n      it(\"should display reject cookies button after reloading page\", () => {\n        cy.restoreLocalStorage();\n        cy.reload();\n        cy.getLocalStorage(\"cookies-accepted\").should(\"equal\", \"true\");\n        cy.get(SELECTORS.REJECT_BUTTON).should(\"be.visible\");\n      });\n    });\n  });\n\n  describe(\"restoring localStorage, when user click rejects cookies button\", () => {\n    it(\"should display accept cookies button\", () => {\n      cy.restoreLocalStorage();\n      cy.reload();\n      cy.getLocalStorage(\"cookies-accepted\").should(\"equal\", \"true\");\n      cy.get(SELECTORS.REJECT_BUTTON).click();\n      cy.getLocalStorage(\"cookies-accepted\").should(\"equal\", \"false\");\n      cy.get(SELECTORS.ACCEPT_BUTTON).should(\"be.visible\");\n      cy.saveLocalStorage();\n    });\n\n    it(\"should display accept-cookies cookies button after reloading page\", () => {\n      cy.restoreLocalStorage();\n      cy.reload();\n      cy.getLocalStorage(\"cookies-accepted\").should(\"equal\", \"false\");\n      cy.get(SELECTORS.ACCEPT_BUTTON).should(\"be.visible\");\n    });\n\n    it(\"should display reject-cookies cookies button after clicking accept-cookies button again\", () => {\n      cy.restoreLocalStorage();\n      cy.reload();\n      cy.getLocalStorage(\"cookies-accepted\").should(\"equal\", \"false\");\n      cy.get(SELECTORS.ACCEPT_BUTTON).click();\n      cy.getLocalStorage(\"cookies-accepted\").should(\"equal\", \"true\");\n      cy.get(SELECTORS.REJECT_BUTTON).should(\"be.visible\");\n      cy.saveLocalStorage();\n    });\n  });\n\n  describe(\"after clearing localStorage snapshot\", () => {\n    before(() => {\n      cy.clearLocalStorageSnapshot();\n    });\n\n    it(\"should display accept cookies button\", () => {\n      cy.restoreLocalStorage();\n      cy.reload();\n      cy.getLocalStorage(\"cookies-accepted\").should(\"not.exist\");\n      cy.get(SELECTORS.ACCEPT_BUTTON).should(\"be.visible\");\n      cy.saveLocalStorage();\n    });\n\n    it(\"should display reject cookies button after clicking button\", () => {\n      cy.restoreLocalStorage();\n      cy.reload();\n      cy.getLocalStorage(\"cookies-accepted\").should(\"not.exist\");\n      cy.get(SELECTORS.ACCEPT_BUTTON).click();\n      cy.getLocalStorage(\"cookies-accepted\").should(\"equal\", \"true\");\n      cy.get(SELECTORS.REJECT_BUTTON).should(\"be.visible\");\n      cy.saveLocalStorage();\n    });\n  });\n\n  describe(\"disabling localStorage\", () => {\n    it(\"should not get previous localStorage value\", () => {\n      cy.disableLocalStorage();\n      cy.reload();\n      cy.restoreLocalStorage();\n      cy.reload();\n      cy.getLocalStorage(\"cookies-accepted\").should(\"not.exist\");\n    });\n\n    it(\"should display warning if localStorage is disabled\", () => {\n      cy.disableLocalStorage();\n      cy.reload();\n      cy.get(SELECTORS.LOCALSTORAGE_DISABLED_WARNING).should(\"be.visible\");\n    });\n\n    it(\"should not set cookiesAccepted localStorage value when user clicks accept cookies button\", () => {\n      cy.disableLocalStorage();\n      cy.reload();\n      cy.getLocalStorage(\"cookies-accepted\").should(\"not.exist\");\n      cy.get(SELECTORS.ACCEPT_BUTTON).click({ force: true });\n      cy.getLocalStorage(\"cookies-accepted\").should(\"not.exist\");\n      // eslint-disable-next-line cypress/no-unnecessary-waiting\n      cy.wait(500);\n      cy.get(SELECTORS.REJECT_BUTTON).should(\"not.exist\");\n    });\n\n    it(\"should not throw when calling to setLocalStorage, getLocalStorage or removeLocalStorage commands\", () => {\n      cy.disableLocalStorage();\n      cy.reload();\n      cy.setLocalStorage(\"user-preferences\", '{\"cookiesAccepted\":false}');\n      cy.getLocalStorage(\"user-preferences\").should(\"not.exist\");\n      cy.removeLocalStorage(\"user-preferences\");\n      cy.getLocalStorage(\"user-preferences\").should(\"not.exist\");\n    });\n\n    it(\"should not throw when calling to restoreLocalStorage\", () => {\n      cy.disableLocalStorage();\n      cy.reload();\n      cy.restoreLocalStorage();\n      cy.getLocalStorage(\"user-preferences\").should(\"not.exist\");\n    });\n\n    it(\"should keep storage disabled in the same test\", () => {\n      cy.setLocalStorage(\"user-preferences\", '{\"cookiesAccepted\":true}');\n      cy.saveLocalStorage();\n      cy.disableLocalStorage();\n      cy.reload();\n      cy.restoreLocalStorage();\n      cy.reload();\n      cy.getLocalStorage(\"user-preferences\").should(\"not.exist\");\n    });\n\n    it(\"should not clear previous localStorage snapshot\", () => {\n      cy.restoreLocalStorage();\n      cy.reload();\n      cy.getLocalStorage(\"user-preferences\").should(\n        \"equal\",\n        '{\"cookiesAccepted\":true}',\n      );\n    });\n\n    it(\"should not throw when reloading multiple times\", () => {\n      cy.disableLocalStorage();\n      cy.reload();\n      cy.getLocalStorage(\"user-preferences\").should(\"not.exist\");\n      cy.disableLocalStorage();\n      cy.reload();\n      cy.getLocalStorage(\"user-preferences\").should(\"not.exist\");\n      cy.restoreLocalStorage();\n      cy.reload();\n      cy.getLocalStorage(\"user-preferences\");\n      cy.disableLocalStorage();\n      cy.reload();\n      cy.getLocalStorage(\"user-preferences\").should(\"not.exist\");\n    });\n  });\n\n  describe(\"when using setLocalStorage command to manually set user-preferences value\", () => {\n    it(\"should display reject cookies button\", () => {\n      cy.setLocalStorage(\"user-preferences\", '{\"cookiesAccepted\":true}');\n      cy.reload();\n      cy.get(SELECTORS.REJECT_BUTTON).should(\"be.visible\");\n      cy.saveLocalStorage();\n    });\n  });\n\n  describe(\"when using getLocalStorage command to manually get localStorage items\", () => {\n    it(\"should return current localStorage values\", () => {\n      cy.restoreLocalStorage();\n      cy.reload();\n      cy.get(SELECTORS.REJECT_BUTTON).should(\"be.visible\");\n      cy.getLocalStorage(\"user-preferences\").should(\n        \"equal\",\n        '{\"cookiesAccepted\":true}',\n      );\n      cy.setLocalStorage(\"user-preferences\", '{\"cookiesAccepted\":false}');\n      cy.getLocalStorage(\"user-preferences\").should(\n        \"equal\",\n        '{\"cookiesAccepted\":false}',\n      );\n      cy.saveLocalStorage();\n    });\n  });\n\n  describe(\"when using removeLocalStorage command to manually remove localStorage item\", () => {\n    it(\"should remove item from localStorage\", () => {\n      cy.restoreLocalStorage();\n      cy.reload();\n      cy.getLocalStorage(\"user-preferences\").should(\n        \"equal\",\n        '{\"cookiesAccepted\":false}',\n      );\n      cy.get(SELECTORS.ACCEPT_BUTTON).should(\"be.visible\");\n      cy.removeLocalStorage(\"user-preferences\");\n      cy.getLocalStorage(\"user-preferences\").should(\"equal\", null);\n    });\n\n    it(\"should have not removed item from localStorage snapshot\", () => {\n      cy.restoreLocalStorage();\n      cy.reload();\n      cy.getLocalStorage(\"user-preferences\").should(\n        \"equal\",\n        '{\"cookiesAccepted\":false}',\n      );\n      cy.get(SELECTORS.ACCEPT_BUTTON).should(\"be.visible\");\n      cy.removeLocalStorage(\"user-preferences\");\n      cy.saveLocalStorage();\n    });\n\n    it(\"should have removed item from localStorage snapshot after saving it\", () => {\n      cy.setLocalStorage(\"user-preferences\", '{\"cookiesAccepted\":true}');\n      cy.reload();\n      cy.get(SELECTORS.REJECT_BUTTON).should(\"be.visible\");\n      cy.restoreLocalStorage();\n      cy.getLocalStorage(\"user-preferences\").should(\"not.exist\");\n    });\n  });\n});\n"
  },
  {
    "path": "test-e2e/cypress-typescript/cypress/e2e/localstorage-disabled.cy.ts",
    "content": "// Next reference is commented as package is not available at node_modules\n//// <reference types=\"cypress-localstorage-commands\" />\n\ndescribe(\"when localStorage is disabled\", () => {\n  beforeEach(() => {\n    cy.disableLocalStorage({\n      withError: new Error(\"Disabled by cypress-localstorage-commands\"),\n    });\n    cy.visit(\"/\");\n  });\n\n  it(\"should display localStorage warning\", () => {\n    cy.get(\"#localstorage-disabled-warning\").should(\"be.visible\");\n  });\n\n  it(\"should display localStorage error message\", () => {\n    cy.get(\"#localstorage-error\").should(\n      \"have.text\",\n      \"Disabled by cypress-localstorage-commands\",\n    );\n  });\n\n  it(\"should display accept-cookies button disabled\", () => {\n    cy.get(\"#accept-cookies\").should(\"be.disabled\");\n  });\n});\n"
  },
  {
    "path": "test-e2e/cypress-typescript/cypress/e2e/named-snapshots.cy.ts",
    "content": "// Next reference is commented as package is not available at node_modules\n//// <reference types=\"cypress-localstorage-commands\" />\n\ndescribe(\"Accept cookies button using named snapshots\", () => {\n  const COOKIES_BUTTON = \"#accept-cookies\";\n\n  before(() => {\n    cy.clearLocalStorageSnapshot();\n  });\n\n  beforeEach(() => {\n    cy.visit(\"/\");\n  });\n\n  it(\"should be visible\", () => {\n    cy.get(COOKIES_BUTTON).should(\"be.visible\");\n    cy.saveLocalStorage(\"cookies-not-accepted\");\n  });\n\n  it(\"should not be visible after clicked\", () => {\n    cy.get(COOKIES_BUTTON).click();\n    cy.get(COOKIES_BUTTON).should(\"not.exist\");\n    cy.saveLocalStorage(\"cookies-accepted\");\n  });\n\n  it(\"should be visible when cookies are not accepted\", () => {\n    cy.restoreLocalStorage(\"cookies-not-accepted\");\n    cy.reload();\n    cy.get(COOKIES_BUTTON).should(\"be.visible\");\n  });\n\n  it(\"should not be visible when cookies are accepted\", () => {\n    cy.restoreLocalStorage(\"cookies-accepted\");\n    cy.reload();\n    cy.get(COOKIES_BUTTON).should(\"not.exist\");\n  });\n\n  it(\"should be visible after clearing localStorage snapshot\", () => {\n    cy.clearLocalStorageSnapshot(\"cookies-accepted\");\n    cy.restoreLocalStorage(\"cookies-accepted\");\n    cy.reload();\n    cy.get(COOKIES_BUTTON).should(\"be.visible\");\n  });\n});\n"
  },
  {
    "path": "test-e2e/cypress-typescript/cypress/support/commands.js",
    "content": "// eslint-disable-next-line import/no-unresolved\nimport \"./cypress-localstorage-commands\";\n"
  },
  {
    "path": "test-e2e/cypress-typescript/cypress/support/e2e.js",
    "content": "// Import commands.js using ES2015 syntax:\nimport \"./commands\";\n\n// Alternatively you can use CommonJS syntax:\n// require('./commands')\n"
  },
  {
    "path": "test-e2e/cypress-typescript/cypress.config.ts",
    "content": "// eslint-disable-next-line @typescript-eslint/no-require-imports\nimport plugin = require(\"./cypress/support/cypress-localstorage-commands/plugin\");\n\nexport default {\n  e2e: {\n    baseUrl: \"http://localhost:3000\",\n    setupNodeEvents(on, config) {\n      plugin(on, config);\n    },\n  },\n  video: false,\n  allowCypressEnv: false,\n};\n"
  },
  {
    "path": "test-e2e/cypress-typescript/package.json",
    "content": "{\n  \"name\": \"cypress-typescript\",\n  \"version\": \"1.0.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"prelint\": \"pnpm run copy:library\",\n    \"lint\": \"eslint scripts cypress\",\n    \"build:serve\": \"cd ../app && pnpm run build:serve\",\n    \"cypress:install\": \"cypress install\",\n    \"cypress:verify\": \"cypress verify\",\n    \"cypress:open\": \"cypress open\",\n    \"cypress:run\": \"cypress run\",\n    \"copy:library\": \"node scripts/copyLibrary.js\",\n    \"build-and-serve-and-cypress\": \"start-server-and-test build:serve http-get://localhost:3000 cypress:run\",\n    \"test:ci\": \"pnpm run copy:library && pnpm run build-and-serve-and-cypress\"\n  },\n  \"devDependencies\": {\n    \"cypress\": \"15.10.0\"\n  }\n}\n"
  },
  {
    "path": "test-e2e/cypress-typescript/scripts/copyLibrary.js",
    "content": "const path = require(\"node:path\");\nconst fsExtra = require(\"fs-extra\");\n\nconst rootPath = path.resolve(__dirname, \"..\");\nconst rootLibPath = path.resolve(rootPath, \"..\", \"..\");\nconst destPath = path.resolve(\n  rootPath,\n  \"cypress\",\n  \"support\",\n  \"cypress-localstorage-commands\",\n);\n\nconst SRC_FOLDER = \"src\";\nconst INDEX_FILE = \"index.js\";\nconst INDEX_TS_FILE = \"index.d.ts\";\nconst PLUGIN_FILE = \"plugin.js\";\nconst PLUGIN_TS_FILE = \"plugin.d.ts\";\n\nconst libPath = path.resolve(rootLibPath, SRC_FOLDER);\nconst indexFile = path.resolve(rootLibPath, INDEX_FILE);\nconst indexTsFile = path.resolve(rootLibPath, INDEX_TS_FILE);\nconst pluginFile = path.resolve(rootLibPath, PLUGIN_FILE);\nconst pluginTsFile = path.resolve(rootLibPath, PLUGIN_TS_FILE);\n\nconst copyLib = () => {\n  fsExtra.removeSync(destPath);\n  fsExtra.ensureDirSync(destPath);\n  fsExtra.copySync(libPath, path.resolve(destPath, SRC_FOLDER));\n  fsExtra.copySync(indexFile, path.resolve(destPath, INDEX_FILE));\n  fsExtra.copySync(indexTsFile, path.resolve(destPath, INDEX_TS_FILE));\n  fsExtra.copySync(pluginFile, path.resolve(destPath, PLUGIN_FILE));\n  fsExtra.copySync(pluginTsFile, path.resolve(destPath, PLUGIN_TS_FILE));\n};\n\ncopyLib();\n"
  },
  {
    "path": "test-e2e/cypress-typescript/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"es6\",\n    \"module\": \"commonjs\",\n    \"outDir\": \"dist\",\n    \"moduleResolution\": \"node\",\n    \"types\": [\"cypress\"]\n  },\n  \"include\": [\n    \"**/*.ts\"\n  ],\n  \"exclude\": [\n    \"node_modules\"\n  ]\n}\n"
  },
  {
    "path": "test-e2e/specs/cypress/e2e/across-specs/restore.cy.js",
    "content": "describe(\"Cookies buttons\", () => {\n  const ACCEPT_BUTTON = \"#accept-cookies\";\n  const REJECT_BUTTON = \"#reject-cookies\";\n\n  beforeEach(() => {\n    cy.restoreLocalStorage();\n    cy.visit(\"/\");\n  });\n\n  it(\"accept should not be visible after loading\", () => {\n    cy.get(ACCEPT_BUTTON).should(\"not.exist\");\n  });\n\n  it(\"reject should be visible\", () => {\n    cy.get(REJECT_BUTTON).should(\"be.visible\");\n  });\n});\n"
  },
  {
    "path": "test-e2e/specs/cypress/e2e/across-specs/save.cy.js",
    "content": "describe(\"Cookies buttons\", () => {\n  const ACCEPT_BUTTON = \"#accept-cookies\";\n  const REJECT_BUTTON = \"#reject-cookies\";\n\n  before(() => {\n    cy.clearLocalStorageSnapshot();\n  });\n\n  beforeEach(() => {\n    cy.restoreLocalStorage();\n    cy.visit(\"/\");\n  });\n\n  afterEach(() => {\n    cy.saveLocalStorage();\n  });\n\n  it(\"accept should be visible\", () => {\n    cy.get(ACCEPT_BUTTON).should(\"be.visible\");\n  });\n\n  it(\"accept should not be visible after clicked\", () => {\n    cy.get(ACCEPT_BUTTON).click();\n    cy.get(ACCEPT_BUTTON).should(\"not.exist\");\n  });\n\n  it(\"reject should not be visible\", () => {\n    cy.get(REJECT_BUTTON).should(\"be.visible\");\n  });\n\n  it(\"reject should still be visible after reloading\", () => {\n    cy.get(REJECT_BUTTON).should(\"be.visible\");\n    cy.get(ACCEPT_BUTTON).should(\"not.exist\");\n  });\n});\n"
  },
  {
    "path": "test-e2e/specs/cypress/e2e/assertions-example.cy.js",
    "content": "describe(\"localStorage cookies-accepted item\", () => {\n  beforeEach(() => {\n    cy.restoreLocalStorage();\n    cy.visit(\"/\");\n  });\n\n  afterEach(() => {\n    cy.saveLocalStorage();\n  });\n\n  it(\"should be null first time page is visited\", () => {\n    cy.getLocalStorage(\"cookies-accepted\").should(\"equal\", null);\n  });\n\n  it(\"should be true after clicking cookies button\", () => {\n    cy.get(\"#accept-cookies\").click();\n    cy.getLocalStorage(\"cookies-accepted\").should(\"equal\", \"true\");\n  });\n\n  it(\"should be true after reloading\", () => {\n    cy.getLocalStorage(\"cookies-accepted\").then((cookiesAccepted) => {\n      expect(cookiesAccepted).to.equal(\"true\");\n    });\n  });\n});\n"
  },
  {
    "path": "test-e2e/specs/cypress/e2e/cookies-example.cy.js",
    "content": "describe(\"Accept cookies button\", () => {\n  const COOKIES_BUTTON = \"#accept-cookies\";\n  const LOCALSTORAGE_DISABLED_WARNING = \"#localstorage-disabled-warning\";\n  const LOCALSTORAGE_ERROR = \"#localstorage-error\";\n\n  before(() => {\n    cy.clearLocalStorageSnapshot();\n  });\n\n  beforeEach(() => {\n    cy.restoreLocalStorage();\n    cy.visit(\"/\");\n  });\n\n  afterEach(() => {\n    cy.saveLocalStorage();\n  });\n\n  it(\"should be visible\", () => {\n    cy.get(COOKIES_BUTTON).should(\"be.visible\");\n  });\n\n  it(\"should not be visible after clicked\", () => {\n    cy.get(COOKIES_BUTTON).click();\n    cy.get(COOKIES_BUTTON).should(\"not.exist\");\n  });\n\n  it(\"should still be visible when reloading if localStorage is disabled\", () => {\n    cy.disableLocalStorage();\n    cy.reload();\n    cy.get(COOKIES_BUTTON).should(\"be.visible\");\n  });\n\n  it(\"should display warning if localStorage is disabled\", () => {\n    cy.disableLocalStorage();\n    cy.reload();\n    cy.get(LOCALSTORAGE_DISABLED_WARNING).should(\"be.visible\");\n  });\n\n  it(\"should display localStorage error message\", () => {\n    cy.disableLocalStorage();\n    cy.reload();\n    cy.get(LOCALSTORAGE_ERROR).should(\"have.text\", \"Error\");\n  });\n\n  it(\"should not be visible after reloading\", () => {\n    cy.get(COOKIES_BUTTON).should(\"not.exist\");\n  });\n});\n"
  },
  {
    "path": "test-e2e/specs/cypress/e2e/cookies.cy.js",
    "content": "describe(\"Cookies\", () => {\n  const SELECTORS = {\n    ACCEPT_BUTTON: \"#accept-cookies\",\n    REJECT_BUTTON: \"#reject-cookies\",\n    LOCALSTORAGE_DISABLED_WARNING: \"#localstorage-disabled-warning\",\n  };\n\n  beforeEach(() => {\n    cy.visit(\"/\");\n  });\n\n  describe(\"when cookies are not accepted\", () => {\n    before(() => {\n      cy.visit(\"/\");\n    });\n\n    it(\"should display accept cookies button\", () => {\n      cy.get(SELECTORS.ACCEPT_BUTTON).should(\"be.visible\");\n    });\n  });\n\n  describe(\"when user click accept cookies button\", () => {\n    describe(\"without using localStorage commands\", () => {\n      it(\"should display reject cookies button\", () => {\n        cy.get(SELECTORS.ACCEPT_BUTTON).click();\n        cy.get(SELECTORS.REJECT_BUTTON).should(\"be.visible\");\n      });\n\n      it(\"should accept cookies button after reloading page\", () => {\n        cy.getLocalStorage(\"cookies-accepted\").should(\"not.exist\");\n        cy.get(SELECTORS.ACCEPT_BUTTON).should(\"be.visible\");\n      });\n    });\n\n    describe(\"saving and restoring local storage\", () => {\n      it(\"should display reject cookies button\", () => {\n        cy.getLocalStorage(\"cookies-accepted\").should(\"not.exist\");\n        cy.get(SELECTORS.ACCEPT_BUTTON).click();\n        cy.getLocalStorage(\"cookies-accepted\").should(\"equal\", \"true\");\n        cy.get(SELECTORS.REJECT_BUTTON).should(\"be.visible\");\n        cy.saveLocalStorage();\n      });\n\n      it(\"should display reject cookies button after reloading page\", () => {\n        cy.restoreLocalStorage();\n        cy.reload();\n        cy.getLocalStorage(\"cookies-accepted\").should(\"equal\", \"true\");\n        cy.get(SELECTORS.REJECT_BUTTON).should(\"be.visible\");\n      });\n    });\n  });\n\n  describe(\"restoring localStorage, when user click rejects cookies button\", () => {\n    it(\"should display accept cookies button\", () => {\n      cy.restoreLocalStorage();\n      cy.reload();\n      cy.getLocalStorage(\"cookies-accepted\").should(\"equal\", \"true\");\n      cy.get(SELECTORS.REJECT_BUTTON).click();\n      cy.getLocalStorage(\"cookies-accepted\").should(\"equal\", \"false\");\n      cy.get(SELECTORS.ACCEPT_BUTTON).should(\"be.visible\");\n      cy.saveLocalStorage();\n    });\n\n    it(\"should display accept-cookies cookies button after reloading page\", () => {\n      cy.restoreLocalStorage();\n      cy.reload();\n      cy.getLocalStorage(\"cookies-accepted\").should(\"equal\", \"false\");\n      cy.get(SELECTORS.ACCEPT_BUTTON).should(\"be.visible\");\n    });\n\n    it(\"should display reject-cookies cookies button after clicking accept-cookies button again\", () => {\n      cy.restoreLocalStorage();\n      cy.reload();\n      cy.getLocalStorage(\"cookies-accepted\").should(\"equal\", \"false\");\n      cy.get(SELECTORS.ACCEPT_BUTTON).click();\n      cy.getLocalStorage(\"cookies-accepted\").should(\"equal\", \"true\");\n      cy.get(SELECTORS.REJECT_BUTTON).should(\"be.visible\");\n      cy.saveLocalStorage();\n    });\n  });\n\n  describe(\"after clearing localStorage snapshot\", () => {\n    before(() => {\n      cy.clearLocalStorageSnapshot();\n    });\n\n    it(\"should display accept cookies button\", () => {\n      cy.restoreLocalStorage();\n      cy.reload();\n      cy.getLocalStorage(\"cookies-accepted\").should(\"not.exist\");\n      cy.get(SELECTORS.ACCEPT_BUTTON).should(\"be.visible\");\n      cy.saveLocalStorage();\n    });\n\n    it(\"should display reject cookies button after clicking button\", () => {\n      cy.restoreLocalStorage();\n      cy.reload();\n      cy.getLocalStorage(\"cookies-accepted\").should(\"not.exist\");\n      cy.get(SELECTORS.ACCEPT_BUTTON).click();\n      cy.getLocalStorage(\"cookies-accepted\").should(\"equal\", \"true\");\n      cy.get(SELECTORS.REJECT_BUTTON).should(\"be.visible\");\n      cy.saveLocalStorage();\n    });\n  });\n\n  describe(\"disabling localStorage\", () => {\n    it(\"should not get previous localStorage value\", () => {\n      cy.disableLocalStorage();\n      cy.reload();\n      cy.restoreLocalStorage();\n      cy.reload();\n      cy.getLocalStorage(\"cookies-accepted\").should(\"not.exist\");\n    });\n\n    it(\"should display warning if localStorage is disabled\", () => {\n      cy.disableLocalStorage();\n      cy.reload();\n      cy.get(SELECTORS.LOCALSTORAGE_DISABLED_WARNING).should(\"be.visible\");\n    });\n\n    it(\"should not set cookiesAccepted localStorage value when user clicks accept cookies button\", () => {\n      cy.disableLocalStorage();\n      cy.reload();\n      cy.getLocalStorage(\"cookies-accepted\").should(\"not.exist\");\n      cy.get(SELECTORS.ACCEPT_BUTTON).click({ force: true });\n      cy.getLocalStorage(\"cookies-accepted\").should(\"not.exist\");\n      // eslint-disable-next-line cypress/no-unnecessary-waiting\n      cy.wait(500);\n      cy.get(SELECTORS.REJECT_BUTTON).should(\"not.exist\");\n    });\n\n    it(\"should not throw when calling to setLocalStorage, getLocalStorage or removeLocalStorage commands\", () => {\n      cy.disableLocalStorage();\n      cy.reload();\n      cy.setLocalStorage(\"user-preferences\", '{\"cookiesAccepted\":false}');\n      cy.getLocalStorage(\"user-preferences\").should(\"not.exist\");\n      cy.removeLocalStorage(\"user-preferences\");\n      cy.getLocalStorage(\"user-preferences\").should(\"not.exist\");\n    });\n\n    it(\"should not throw when calling to restoreLocalStorage\", () => {\n      cy.disableLocalStorage();\n      cy.reload();\n      cy.restoreLocalStorage();\n      cy.getLocalStorage(\"user-preferences\").should(\"not.exist\");\n    });\n\n    it(\"should keep storage disabled in the same test\", () => {\n      cy.setLocalStorage(\"user-preferences\", '{\"cookiesAccepted\":true}');\n      cy.saveLocalStorage();\n      cy.disableLocalStorage();\n      cy.reload();\n      cy.restoreLocalStorage();\n      cy.reload();\n      cy.getLocalStorage(\"user-preferences\").should(\"not.exist\");\n    });\n\n    it(\"should not clear previous localStorage snapshot\", () => {\n      cy.restoreLocalStorage();\n      cy.reload();\n      cy.getLocalStorage(\"user-preferences\").should(\n        \"equal\",\n        '{\"cookiesAccepted\":true}',\n      );\n    });\n\n    it(\"should not throw when reloading multiple times\", () => {\n      cy.disableLocalStorage();\n      cy.reload();\n      cy.getLocalStorage(\"user-preferences\").should(\"not.exist\");\n      cy.disableLocalStorage();\n      cy.reload();\n      cy.getLocalStorage(\"user-preferences\").should(\"not.exist\");\n      cy.restoreLocalStorage();\n      cy.reload();\n      cy.getLocalStorage(\"user-preferences\");\n      cy.disableLocalStorage();\n      cy.reload();\n      cy.getLocalStorage(\"user-preferences\").should(\"not.exist\");\n    });\n  });\n\n  describe(\"when using setLocalStorage command to manually set user-preferences value\", () => {\n    it(\"should display reject cookies button\", () => {\n      cy.setLocalStorage(\"user-preferences\", '{\"cookiesAccepted\":true}');\n      cy.reload();\n      cy.get(SELECTORS.REJECT_BUTTON).should(\"be.visible\");\n      cy.saveLocalStorage();\n    });\n  });\n\n  describe(\"when using getLocalStorage command to manually get localStorage items\", () => {\n    it(\"should return current localStorage values\", () => {\n      cy.restoreLocalStorage();\n      cy.reload();\n      cy.get(SELECTORS.REJECT_BUTTON).should(\"be.visible\");\n      cy.getLocalStorage(\"user-preferences\").should(\n        \"equal\",\n        '{\"cookiesAccepted\":true}',\n      );\n      cy.setLocalStorage(\"user-preferences\", '{\"cookiesAccepted\":false}');\n      cy.getLocalStorage(\"user-preferences\").should(\n        \"equal\",\n        '{\"cookiesAccepted\":false}',\n      );\n      cy.saveLocalStorage();\n    });\n  });\n\n  describe(\"when using removeLocalStorage command to manually remove localStorage item\", () => {\n    it(\"should remove item from localStorage\", () => {\n      cy.restoreLocalStorage();\n      cy.reload();\n      cy.getLocalStorage(\"user-preferences\").should(\n        \"equal\",\n        '{\"cookiesAccepted\":false}',\n      );\n      cy.get(SELECTORS.ACCEPT_BUTTON).should(\"be.visible\");\n      cy.removeLocalStorage(\"user-preferences\");\n      cy.getLocalStorage(\"user-preferences\").should(\"equal\", null);\n    });\n\n    it(\"should have not removed item from localStorage snapshot\", () => {\n      cy.restoreLocalStorage();\n      cy.reload();\n      cy.getLocalStorage(\"user-preferences\").should(\n        \"equal\",\n        '{\"cookiesAccepted\":false}',\n      );\n      cy.get(SELECTORS.ACCEPT_BUTTON).should(\"be.visible\");\n      cy.removeLocalStorage(\"user-preferences\");\n      cy.saveLocalStorage();\n    });\n\n    it(\"should have removed item from localStorage snapshot after saving it\", () => {\n      cy.setLocalStorage(\"user-preferences\", '{\"cookiesAccepted\":true}');\n      cy.reload();\n      cy.get(SELECTORS.REJECT_BUTTON).should(\"be.visible\");\n      cy.restoreLocalStorage();\n      cy.getLocalStorage(\"user-preferences\").should(\"not.exist\");\n    });\n  });\n});\n"
  },
  {
    "path": "test-e2e/specs/cypress/e2e/localstorage-disabled.cy.js",
    "content": "describe(\"when localStorage is disabled\", () => {\n  beforeEach(() => {\n    cy.disableLocalStorage({\n      withError: new Error(\"Disabled by cypress-localstorage-commands\"),\n    });\n    cy.visit(\"/\");\n  });\n\n  it(\"should display localStorage warning\", () => {\n    cy.get(\"#localstorage-disabled-warning\").should(\"be.visible\");\n  });\n\n  it(\"should display localStorage error message\", () => {\n    cy.get(\"#localstorage-error\").should(\n      \"have.text\",\n      \"Disabled by cypress-localstorage-commands\",\n    );\n  });\n\n  it(\"should display accept-cookies button disabled\", () => {\n    cy.get(\"#accept-cookies\").should(\"be.disabled\");\n  });\n});\n"
  },
  {
    "path": "test-e2e/specs/cypress/e2e/named-across-specs/restore-after-clear.cy.js",
    "content": "describe(\"Cookies buttons\", () => {\n  const ACCEPT_BUTTON = \"#accept-cookies\";\n\n  it(\"accept should be visible after clearing localStorage snapshot\", () => {\n    cy.restoreLocalStorage(\"cookies-accepted\");\n    cy.visit(\"/\");\n    cy.get(ACCEPT_BUTTON).should(\"be.visible\");\n  });\n});\n"
  },
  {
    "path": "test-e2e/specs/cypress/e2e/named-across-specs/restore.cy.js",
    "content": "describe(\"Cookies buttons\", () => {\n  const ACCEPT_BUTTON = \"#accept-cookies\";\n\n  it(\"accept should not be visible after loading\", () => {\n    cy.restoreLocalStorage(\"cookies-accepted\");\n    cy.visit(\"/\");\n    cy.get(ACCEPT_BUTTON).should(\"not.exist\");\n  });\n\n  it(\"accept should be visible after clearing localStorage snapshot\", () => {\n    cy.clearLocalStorageSnapshot(\"cookies-accepted\");\n    cy.restoreLocalStorage(\"cookies-accepted\");\n    cy.visit(\"/\");\n    cy.get(ACCEPT_BUTTON).should(\"be.visible\");\n  });\n});\n"
  },
  {
    "path": "test-e2e/specs/cypress/e2e/named-across-specs/save.cy.js",
    "content": "describe(\"Cookies buttons\", () => {\n  const ACCEPT_BUTTON = \"#accept-cookies\";\n\n  before(() => {\n    cy.clearLocalStorageSnapshot();\n  });\n\n  beforeEach(() => {\n    cy.visit(\"/\");\n  });\n\n  it(\"accept should be visible\", () => {\n    cy.get(ACCEPT_BUTTON).should(\"be.visible\");\n    cy.saveLocalStorage(\"cookies-not-accepted\");\n  });\n\n  it(\"accept should not be visible after clicked\", () => {\n    cy.get(ACCEPT_BUTTON).click();\n    cy.get(ACCEPT_BUTTON).should(\"not.exist\");\n    cy.saveLocalStorage(\"cookies-accepted\");\n  });\n\n  it(\"accept should be visible when cookies are not accepted\", () => {\n    cy.restoreLocalStorage(\"cookies-not-accepted\");\n    cy.visit(\"/\");\n    cy.get(ACCEPT_BUTTON).should(\"be.visible\");\n  });\n\n  it(\"should not be visible when cookies are accepted\", () => {\n    cy.restoreLocalStorage(\"cookies-accepted\");\n    cy.visit(\"/\");\n    cy.get(ACCEPT_BUTTON).should(\"not.exist\");\n  });\n});\n"
  },
  {
    "path": "test-e2e/specs/cypress/e2e/named-snapshots.cy.js",
    "content": "describe(\"Accept cookies button using named snapshots\", () => {\n  const COOKIES_BUTTON = \"#accept-cookies\";\n\n  before(() => {\n    cy.clearLocalStorageSnapshot();\n    cy.visit(\"/\");\n  });\n\n  beforeEach(() => {\n    cy.visit(\"/\");\n  });\n\n  it(\"should be visible\", () => {\n    cy.get(COOKIES_BUTTON).should(\"be.visible\");\n    cy.saveLocalStorage(\"cookies-not-accepted\");\n  });\n\n  it(\"should not be visible after clicked\", () => {\n    cy.get(COOKIES_BUTTON).click();\n    cy.get(COOKIES_BUTTON).should(\"not.exist\");\n    cy.saveLocalStorage(\"cookies-accepted\");\n  });\n\n  it(\"should be visible when cookies are not accepted\", () => {\n    cy.restoreLocalStorage(\"cookies-not-accepted\");\n    cy.reload();\n    cy.get(COOKIES_BUTTON).should(\"be.visible\");\n  });\n\n  it(\"should not be visible when cookies are accepted\", () => {\n    cy.restoreLocalStorage(\"cookies-accepted\");\n    cy.reload();\n    cy.get(COOKIES_BUTTON).should(\"not.exist\");\n  });\n\n  it(\"should be visible after clearing localStorage snapshot\", () => {\n    cy.clearLocalStorageSnapshot(\"cookies-accepted\");\n    cy.restoreLocalStorage(\"cookies-accepted\");\n    cy.reload();\n    cy.get(COOKIES_BUTTON).should(\"be.visible\");\n  });\n});\n"
  },
  {
    "path": "test-e2e/specs/cypress/e2e/no-across-specs/restore.cy.js",
    "content": "describe(\"Cookies buttons\", () => {\n  const ACCEPT_BUTTON = \"#accept-cookies\";\n  const REJECT_BUTTON = \"#reject-cookies\";\n\n  beforeEach(() => {\n    cy.restoreLocalStorage();\n    cy.visit(\"/\");\n  });\n\n  it(\"accept should be visible after loading\", () => {\n    cy.get(ACCEPT_BUTTON).should(\"be.visible\");\n  });\n\n  it(\"reject should not exist\", () => {\n    cy.get(REJECT_BUTTON).should(\"not.exist\");\n  });\n});\n"
  },
  {
    "path": "test-e2e/specs/cypress/e2e/no-across-specs/save.cy.js",
    "content": "describe(\"Cookies buttons\", () => {\n  const ACCEPT_BUTTON = \"#accept-cookies\";\n  const REJECT_BUTTON = \"#reject-cookies\";\n\n  before(() => {\n    cy.clearLocalStorageSnapshot();\n  });\n\n  beforeEach(() => {\n    cy.restoreLocalStorage();\n    cy.visit(\"/\");\n  });\n\n  afterEach(() => {\n    cy.saveLocalStorage();\n  });\n\n  it(\"accept should be visible\", () => {\n    cy.get(ACCEPT_BUTTON).should(\"be.visible\");\n  });\n\n  it(\"accept should not be visible after clicked\", () => {\n    cy.get(ACCEPT_BUTTON).click();\n    cy.get(ACCEPT_BUTTON).should(\"not.exist\");\n  });\n\n  it(\"reject should not be visible\", () => {\n    cy.get(REJECT_BUTTON).should(\"be.visible\");\n  });\n\n  it(\"reject should still be visible after reloading\", () => {\n    cy.get(REJECT_BUTTON).should(\"be.visible\");\n    cy.get(ACCEPT_BUTTON).should(\"not.exist\");\n  });\n});\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"es6\",\n    \"module\": \"commonjs\",\n    \"outDir\": \"dist\",\n    \"moduleResolution\": \"node\",\n    \"types\": [\"cypress\"],\n    \"skipLibCheck\": true\n  },\n  \"include\": [\n    \"*.ts\",\n    \"test-e2e/**/integration/*.ts\"\n  ],\n  \"exclude\": [\n    \"node_modules\",\n    \"**/node_modules\"\n  ]\n}\n"
  }
]