master 189aa6b5c18b cached
137 files
139.9 KB
39.7k tokens
58 symbols
1 requests
Download .txt
Repository: javierbrea/cypress-localstorage-commands
Branch: master
Commit: 189aa6b5c18b
Files: 137
Total size: 139.9 KB

Directory structure:
gitextract_54gauqw_/

├── .github/
│   ├── CODE_OF_CONDUCT.md
│   ├── CONTRIBUTING.md
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.md
│   │   └── feature_request.md
│   ├── PULL_REQUEST_TEMPLATE.md
│   └── workflows/
│       ├── build.yml
│       ├── check-package-version.yml
│       ├── publish-to-github.yml
│       └── publish-to-npm.yml
├── .gitignore
├── .husky/
│   ├── .gitignore
│   └── pre-commit
├── .vscode/
│   └── settings.json
├── CHANGELOG.md
├── LICENSE
├── README.md
├── cspell/
│   └── missing.txt
├── cspell.config.js
├── eslint.config.mjs
├── index.d.ts
├── index.js
├── jest.config.js
├── package.json
├── plugin.d.ts
├── plugin.js
├── pnpm-workspace.yaml
├── renovate.json
├── sonar-project.properties
├── src/
│   ├── LocalStorage.js
│   ├── constants.js
│   ├── plugin.js
│   └── register.js
├── stryker.conf.js
├── test/
│   ├── Cy.mock.js
│   ├── Cypress.mock.js
│   ├── LocalStorage.mock.js
│   ├── LocalStorage.spec.js
│   ├── LocalStorageNode.spec.js
│   └── register.spec.js
├── test-e2e/
│   ├── app/
│   │   ├── .gitignore
│   │   ├── package.json
│   │   ├── public/
│   │   │   └── index.html
│   │   ├── serve.json
│   │   └── src/
│   │       ├── App.css
│   │       ├── App.js
│   │       ├── components/
│   │       │   ├── cookies-button/
│   │       │   │   ├── CookiesButton.css
│   │       │   │   ├── CookiesButton.js
│   │       │   │   └── index.js
│   │       │   └── cookies-value/
│   │       │       ├── CookiesValue.js
│   │       │       └── index.js
│   │       ├── data/
│   │       │   └── user-preferences/
│   │       │       ├── actions.js
│   │       │       ├── index.js
│   │       │       ├── origins.js
│   │       │       └── selectors.js
│   │       ├── index.css
│   │       ├── index.js
│   │       └── modules/
│   │           ├── accept-cookies/
│   │           │   ├── AcceptCookies.js
│   │           │   └── index.js
│   │           ├── cookies-value/
│   │           │   ├── CookiesValue.js
│   │           │   └── index.js
│   │           ├── localstorage-warning/
│   │           │   ├── LocalStorageWarning.css
│   │           │   ├── LocalStorageWarning.js
│   │           │   └── index.js
│   │           └── reject-cookies/
│   │               ├── RejectCookies.js
│   │               └── index.js
│   ├── cypress-14/
│   │   ├── .gitignore
│   │   ├── babel.config.js
│   │   ├── cypress/
│   │   │   ├── plugins/
│   │   │   │   └── index.js
│   │   │   └── support/
│   │   │       ├── commands.js
│   │   │       └── e2e.js
│   │   ├── cypress.config.js
│   │   └── package.json
│   ├── cypress-14-no-plugin/
│   │   ├── .gitignore
│   │   ├── babel.config.js
│   │   ├── cypress/
│   │   │   ├── plugins/
│   │   │   │   └── index.js
│   │   │   └── support/
│   │   │       ├── commands.js
│   │   │       └── e2e.js
│   │   ├── cypress.config.js
│   │   └── package.json
│   ├── cypress-9/
│   │   ├── .gitignore
│   │   ├── babel.config.js
│   │   ├── cypress/
│   │   │   ├── .eslintrc.json
│   │   │   ├── plugins/
│   │   │   │   └── index.js
│   │   │   └── support/
│   │   │       ├── commands.js
│   │   │       └── index.js
│   │   ├── cypress.config.js
│   │   ├── package.json
│   │   └── scripts/
│   │       └── copySpecs.js
│   ├── cypress-9-no-plugin/
│   │   ├── .gitignore
│   │   ├── babel.config.js
│   │   ├── cypress/
│   │   │   ├── .eslintrc.json
│   │   │   ├── plugins/
│   │   │   │   └── index.js
│   │   │   └── support/
│   │   │       ├── commands.js
│   │   │       └── index.js
│   │   ├── cypress.config.js
│   │   ├── package.json
│   │   └── scripts/
│   │       └── copySpecs.js
│   ├── cypress-latest/
│   │   ├── .gitignore
│   │   ├── babel.config.js
│   │   ├── cypress/
│   │   │   ├── plugins/
│   │   │   │   └── index.js
│   │   │   └── support/
│   │   │       ├── commands.js
│   │   │       └── e2e.js
│   │   ├── cypress.config.js
│   │   └── package.json
│   ├── cypress-latest-no-plugin/
│   │   ├── .gitignore
│   │   ├── babel.config.js
│   │   ├── cypress/
│   │   │   ├── plugins/
│   │   │   │   └── index.js
│   │   │   └── support/
│   │   │       ├── commands.js
│   │   │       └── e2e.js
│   │   ├── cypress.config.js
│   │   └── package.json
│   ├── cypress-typescript/
│   │   ├── .eslintignore
│   │   ├── .gitignore
│   │   ├── cypress/
│   │   │   ├── e2e/
│   │   │   │   ├── assertions-example.cy.ts
│   │   │   │   ├── cookies-example.cy.ts
│   │   │   │   ├── cookies.cy.ts
│   │   │   │   ├── localstorage-disabled.cy.ts
│   │   │   │   └── named-snapshots.cy.ts
│   │   │   └── support/
│   │   │       ├── commands.js
│   │   │       └── e2e.js
│   │   ├── cypress.config.ts
│   │   ├── package.json
│   │   ├── scripts/
│   │   │   └── copyLibrary.js
│   │   └── tsconfig.json
│   └── specs/
│       └── cypress/
│           └── e2e/
│               ├── across-specs/
│               │   ├── restore.cy.js
│               │   └── save.cy.js
│               ├── assertions-example.cy.js
│               ├── cookies-example.cy.js
│               ├── cookies.cy.js
│               ├── localstorage-disabled.cy.js
│               ├── named-across-specs/
│               │   ├── restore-after-clear.cy.js
│               │   ├── restore.cy.js
│               │   └── save.cy.js
│               ├── named-snapshots.cy.js
│               └── no-across-specs/
│                   ├── restore.cy.js
│                   └── save.cy.js
└── tsconfig.json

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct

## Our Pledge

In 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.

## Our Standards

Examples of behavior that contributes to creating a positive environment include:

* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members

Examples of unacceptable behavior by participants include:

* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting

## Our Responsibilities

Project 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.

Project 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.

## Scope

This 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.

## Enforcement

Instances 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.

Project 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.

## Attribution

This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]

[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/


================================================
FILE: .github/CONTRIBUTING.md
================================================
# Contributing

First off, thanks for taking the time to contribute!

The 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.

#### Table Of Contents

* [Code of Conduct](#code-of-conduct)
* [Project governance](#project-governance)
  * [Rules](#rules)
  * [Releases](#releases)
  * [Changes to this arrangement](#changes-to-this-arrangement)
* [Pull Requests](#pull-requests)
* [Styleguides](#styleguides)
  * [Git Commit Messages](#git-commit-messages)
  * [JavaScript Styleguide](#javascript-styleguide)
  * [Tests Styleguide](#tests-styleguide)
* [Developer's certificate of origin](#developers-certificate-of-origin)

## Code of Conduct

This 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.

## Project Governance

Individuals making significant and valuable contributions are given commit-access to the project to contribute as they see fit.

### Rules

There are a few basic ground-rules for contributors:

1. **No `--force` pushes** or modifying the Git history in any way.
2. **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.
3. **All changes** to this project will be documented in the GHANGELOG.md file.

### Releases

Declaring formal releases remains the prerogative of the project maintainer. 

### Changes to this arrangement

This document may also be subject to pull-requests or changes by contributors where you believe you have something valuable to add or change.

## Pull Requests

* Fill in [the required template](PULL_REQUEST_TEMPLATE.md).
* Do not include issue numbers in the PR title.
* Follow the [JavaScript styleguide](#javascript-styleguide).
* Follow the [Tests styleguide](#tests-styleguide).
* All enhancements and bug fixes must be accompanied with all needed new related regression test.
* Coverage of unit tests must remain 100%.
* Run tests often. Tests are ran automatically with Travis when you push, but you still need to run them locally before pushing.
* Document new features, or update documentation if changes affect to it.
* End all files with a newline.
* Place requires in the following order:
    * Built in Node Modules (such as `path`)
    * NPM Modules (such as `lodash`)
    * Local Modules (using relative paths)

## Styleguides

### Git Commit Messages

* Use the present tense ("Add feature" not "Added feature")
* Use the imperative mood ("Move cursor to..." not "Moves cursor to...")
* Limit the first line to 72 characters or less
* Reference issues and pull requests liberally after the first line

### JavaScript Styleguide

All JavaScript must adhere to the style defined in the `.eslintrc.js` file.

### Tests Styleguide

- Fail tests first. How do you know if it is actually testing anything if the assert never failed?
- Treat `describe` as a noun or situation (Situations usually start with "when").
- Treat `it` as a statement about state or how an operation changes state. Usually, all `it` should start with "should".
- Prefer fewer asserts per `it`.
- 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`)

#### Example

```js
describe("a dog", () => {
  describe("when is happy", () => {
    it("should wags its tail", () => {
      expect(dog.tail.moving).to.be.true();
    });
  });
});
```

## Developer's Certificate of Origin

By making a contribution to this project, I certify that:

- (a) The contribution was created in whole or in part by me and I have the right to
  submit it under the open source license indicated in the file; or

- (b) The contribution is based upon previous work that, to the best of my knowledge, is
  covered under an appropriate open source license and I have the right under that license
  to submit that work with modifications, whether created in whole or in part by me, under
  the same open source license (unless I am permitted to submit under a different
  license), as indicated in the file; or

- (c) The contribution was provided directly to me by some other person who certified
  (a), (b) or (c) and I have not modified it.

- (d) I understand and agree that this project and the contribution are public and that a
  record of the contribution (including all personal information I submit with it,
  including my sign-off) is maintained indefinitely and may be redistributed consistent
  with this project or the open source license(s) involved.


================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve

---

**Describe the bug**
A clear and concise description of what the bug is.

**To Reproduce**
Steps to reproduce the behavior

**Expected behavior**
A clear and concise description of what you expected to happen.

**Logs**
If applicable, add logs to help explain your problem.

** Operating system, Node.js an npm versions, or browser version (please complete the following information):**
 - OS: [e.g. Ubuntu 18.04]
 - Node.js: [e.g. 8.11.1]
 - npm: [e.g. 5.6.0]
 - Browser: [e.g. Chrome 73.0.3683]

**Additional context**
Add any other context about the problem here.


================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest an idea for this project

---

**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

**Describe the solution you'd like**
A clear and concise description of what you want to happen.

**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.

**Additional context**
Add any other context or examples about the feature request here.


================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
**IMPORTANT: Please do not create a Pull Request without creating an issue first.**

*Any change needs to be discussed before proceeding. Failure to do so may result in the rejection of the pull request.*

Please provide enough information so that others can review your pull request:

Explain the **details** for making this change. What existing problem does the pull request solve?

**Closing issues**

Put `closes #XXXX` in your comment to auto-close the issue that your PR fixes.


================================================
FILE: .github/workflows/build.yml
================================================
name: build
on:
  push:
    branches:
      - master
      - release
  pull_request:
concurrency:  
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true
jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node: ["20.13.1", "22.2.0", "24.4.1"]
    steps:
      - name: Checkout
        uses: actions/checkout@v4
      - name: Extract branch name
        shell: bash
        run: echo "branch=$(echo ${GITHUB_REF##*/})" >> $GITHUB_OUTPUT
        id: extract-branch
      - name: Install pnpm
        uses: pnpm/action-setup@v4
      - name: Install Node.js
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node }}
      - name: Install dependencies
        run: pnpm install
      - name: Check spelling
        if: ${{ matrix.node == '24.4.1' }}
        run: pnpm run cspell
      - name: Lint
        if: ${{ matrix.node == '24.4.1' }}
        run: pnpm run lint
      - name: Check types
        if: ${{ matrix.node == '24.4.1' }}
        run: pnpm run tsc
      - name: Test unit
        run: pnpm run test:unit
      - name: Test mutation
        if: ${{ matrix.node == '24.4.1' }}
        run: pnpm run test:mutation
        env:
          BRANCH_NAME: ${{ steps.extract-branch.outputs.branch }}
          STRYKER_DASHBOARD_API_KEY: ${{ secrets.STRYKER_TOKEN }}
      - name: Test E2E
        run: pnpm run test:e2e
        id: test-e2e
      - name: Upload E2E tests screenshots
        if: ${{ always() && steps.test-e2e.outcome == 'failure' }}
        uses: actions/upload-artifact@v4
        with:
          name: e2e-screenshots-${{ matrix.node }}
          path: test-e2e/react-app/cypress/screenshots
          retention-days: 7
      - name: Upload typescript E2E tests screenshots
        if: ${{ always() && steps.test-e2e.outcome == 'failure' }}
        uses: actions/upload-artifact@v4
        with:
          name: e2e-typescript-screenshots-${{ matrix.node }}
          path: test-e2e/typescript/cypress/screenshots
          retention-days: 7
      - name: Upload test results
        uses: actions/upload-artifact@v4
        with:
          name: coverage-${{ matrix.node }}
          path: coverage
          retention-days: 1
  quality:
    runs-on: ubuntu-latest
    needs: test
    env:
      SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Download test results
        uses: actions/download-artifact@v4
        with:
          name: coverage-22.2.0
          path: coverage
      - name: Coveralls
        uses: coverallsapp/github-action@master
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
      - name: SonarCloud Scan
        if: env.SONAR_TOKEN != ''
        uses: SonarSource/sonarqube-scan-action@v6
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}


================================================
FILE: .github/workflows/check-package-version.yml
================================================
name: check-package-version
on:
  pull_request:
    branches:
      - master
jobs:
  check-package-version:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4
      - name: Get version is new
        id: check
        uses: EndBug/version-check@v2.1.1
        with:
          diff-search: true
          file-name: ./package.json
          file-url: https://unpkg.com/cypress-localstorage-commands@latest/package.json
          static-checking: localIsNew
      - name: Check version is new
        if: steps.check.outputs.changed != 'true'
        run: |
          echo "Version not changed"
          exit 1
      - name: Get version
        id: package-version
        uses: martinbeentjes/npm-get-version-action@v1.3.1
      - name: Check Changelog version
        id: changelog_reader
        uses: mindsers/changelog-reader-action@v2.2.3
        with:
          version: ${{ steps.package-version.outputs.current-version }}
          path: ./CHANGELOG.md
      - name: Read version from Sonar config
        id: sonar-version
        uses: christian-draeger/read-properties@1.1.1
        with:
          path: './sonar-project.properties'
          properties: 'sonar.projectVersion'
      - name: Check Sonar version
        if: steps.sonar-version.outputs.sonar-projectVersion != steps.package-version.outputs.current-version
        run: |
          echo "Version not changed"
          exit 1


================================================
FILE: .github/workflows/publish-to-github.yml
================================================
name: publish-to-github
on:
  release:
    types: [created]
jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
    - name: Checkout
      uses: actions/checkout@v4
    # Setup .npmrc file to publish to GitHub Packages
    - name: Install pnpm
      uses: pnpm/action-setup@v4
    - name: Install Node.js
      uses: actions/setup-node@v4
      with:
        node-version: "22.x"
        registry-url: 'https://npm.pkg.github.com'
        # Defaults to the user or organization that owns the workflow file
        scope: '@javierbrea'
    - name: Change package name
      uses: MerthinTechnologies/edit-json-action@v1
      with:
        filename: './package.json'
        key: 'name'
        value: '@javierbrea/cypress-localstorage-commands'
    - name: Install dependencies
      run: pnpm install
    - name: Publish package
      run: pnpm -r publish --no-git-checks
      env:
        NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}


================================================
FILE: .github/workflows/publish-to-npm.yml
================================================
name: publish-to-npm
on:
  release:
    types: [created]
jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
    - name: Checkout
      uses: actions/checkout@v4
    - name: Install pnpm
      uses: pnpm/action-setup@v4
    - name: Install Node.js
      uses: actions/setup-node@v4
      with:
        node-version: "22.x"
        registry-url: 'https://registry.npmjs.org/'
    - name: Install dependencies
      run: pnpm install
    - name: Publish package
      run: pnpm -r publish --no-git-checks
      env:
        NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}


================================================
FILE: .gitignore
================================================
# See https://help.github.com/ignore-files/ for more about ignoring files.

#environment variables
/.env

# dependencies
/node_modules

# tests
/coverage
/dist

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*

# ides
.idea
.vs

# stryker temp files
/reports
.stryker-tmp
stryker.conf.local.js

# caches
.eslintcache


================================================
FILE: .husky/.gitignore
================================================
_


================================================
FILE: .husky/pre-commit
================================================
pnpm run lint-staged


================================================
FILE: .vscode/settings.json
================================================
{
  "sonarlint.connectedMode.project": {
      "connectionId": "javierbrea",
      "projectKey": "javierbrea_cypress-localstorage-commands"
  }
}


================================================
FILE: CHANGELOG.md
================================================
# Change Log
All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).

## [unreleased]
### Added
### Changed
### Fixed
### Removed

## [2.3.0] - 2026-03-16

### Added

- 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).

### Changed

- 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.
- refactor: Fix minor Sonar issues.
- chore(deps): Upgrade devDependencies
- chore: Run linter, check spelling and check types only in the latest Node version in build workflow

## [2.2.8] - 2025-07-28

### Changed
* test: Upgrade latest Cypress version in E2E tests to v14
* chore(deps): Upgrade dev dependencies
* chore(deps): Remove Node 18 from workflows. Add Node 24
* chore(deps): Add pnpm as package manager to package.json. Remove pnpm version from workflows

## [2.2.7] - 2024-12-06

### Added
* chore: Check spelling in build workflow

### Changed
* chore: Use Pnpm as package manager
* chore: Upgrade eslint configuration to v9
* chore: Update devDependencies

### Fixed
* docs: Fix typos in README

## [2.2.6] - 2024-05-17

### Added
* chore: Handle jobs concurrency in build workflow

### Changed
* chore: Remove usage of "set-output" in build workflow
* chore(deps): Update devDependencies

## [2.2.5] - 2023-11-15

### Changed
- chore(deps): Update devDependencies

## [2.2.4] - 2023-08-14

### Changed
- chore(deps): Update devDependencies

## [2.2.3] - 2023-04-03

### Changed
- chore(deps): Update devDependencies

## [2.2.2] - 2022-12-07

### Added
- docs: Add alternatives

### Changed
- chore(deps): Update devDependencies
- test(e2e): Rename cypress-10 folder to cypress-latest
- test(e2e): Use Cypress 12 in E2E tests

## [2.2.1] - 2022-08-30

### Changed
- chore(deps): Update devDependencies

## [2.2.0] - 2022-07-26

### Added
- feat(#401): Support preserving localStorage across spec files. Node events must be installed to support this feature.

### Changed
- docs: Update docs with installation method in Cypress v10. Add notes about installing it in prior versions.
- chore(deps): Update devDependencies
- test(e2e): Add E2E tests using different Cypress versions

## [2.1.0] - 2022-06-02

### Changed
- chore: Update Cypress devDependency to v10
- test: Use Cypress v10 for running plugin e2e tests. Update configuration.
- chore: Update github actions versions

## [2.0.0] - 2022-05-30

### Removed
- chore: Drop NodeJs 12 support
- docs: Remove Fossa badge

### Changed
- chore: Remove NodeJs v12 from tests workflow. Add NodeJs v18
- chore(deps): Update devDependencies

## [1.7.0] - 2022-02-22

### Added
- feat(#376): Support multiple snapshots allowing to define a name in save, restore and clear commands.
- chore: Add command to check types. Run it in build workflow
- chore: Add eslint plugins

### Removed
- docs: Remove broken dependencies badge

### Changed
- chore: Remove NodeJs v15 from tests workflow. Add NodeJs v17
- chore(deps): Update devDependencies

## [1.6.1] - 2021-11-11
### Changed
- chore(#382): Use Cypress v9 in E2E tests
- chore(#382): Support any Cypress version greater than 2.1.0
- chore(deps): Update devDependencies

## [1.6.0] - 2021-11-01
### Changed
- chore(deps): Update devDependencies
- chore(deps): Support any NodeJs version greater than 10.x.

## [1.5.0] - 2021-07-21
### Added
- chore(#330): Use Cypress v8 in E2E tests. Add Cypress v8.x to peerDependencies

### Changed
- chore(deps): Update devDependencies

## [1.4.5] - 2021-05-29

### Changed
- chore(deps): Update devDependencies
- chore: Migrate Sonar project

## [1.4.4] - 2021-04-29

### Added
- chore(deps): Support Node v16.x in engines. Run tests also in node 16.0.0

### Changed
- chore(deps): Update devDependencies

## [1.4.3] - 2021-04-07

### Added
- chore(deps): Support Cypress v7.x in peerDependencies

### Changed
- test(e2e): Run e2e tests in Cypress v7.x
- chore(pipelines): Update node versions
- chore(pipelines): Do not run tests in Node 10, because it is not supported by Cypress v7.x
- chore(deps): Update devDependencies

## [1.4.2] - 2021-03-31

### Changed
- chore(deps): Update devDependencies

## [1.4.1] - 2021-02-24

### Changed
- chore(deps): Update devDependencies
- test: Refactor Sonar smells

## [1.4.0] - 2021-01-17

### Added
- chore: Add types property to package.json (#232)

### Changed
- chore(deps): Update devDependencies
- test(e2e): Adapt testing react app code to [data-provider v3](https://www.data-provider.org/docs/guides-migrating-from-v2-to-v3)

## [1.3.1] - 2020-12-11

### Changed
- chore(#210): Support all Node.js releases that have not passed their end date
- chore(deps): Update devDependencies
- chore(ci): Do not execute SonarCloud on PRs from forks

### Fixed
- docs(readme): Fix build badge url

## [1.3.0] - 2020-12-07

### Added
- feat(#191): Add disableLocalStorage command (Thanks to @Uninen for his contribution).

### Changed
- chore(deps): Update some devDependencies

### Fixed
- style(lint): Lint also files in root folder. Fix jest.config style

## [1.2.5] - 2020-12-05

### Changed
- chore(ci): Migrate CI to github actions. Rename npm commands
- chore(deps): Add Cypress 6.x to peerDependencies
- chore(test): Update Cypress to v6.0.1 in e2e tests
- chore(deps): Update devDependencies

## [1.2.4] - 2020-10-29

### Added
- chore(deps): Add node engine dep option for node@v15.x

### Changed
- chore(deps): Update devDependencies

## [1.2.3] - 2020-10-19

### Changed
- chore(deps): Update devDependencies
- test(cypress): Do not use "be" as assertion in Cypress tests as it is no longer supported
- chore(deps): Modify Stryker config to adapt it to Stryker 4.0 version

## [1.2.2] - 2020-08-27

### Changed
- chore(deps): Add Cypress ^5.0.0 to peerDependencies
- chore(deps): Update devDependencies

## [1.2.1] - 2020-06-09

### Fixed
- fix(TypeScript): Fix TypeScript return types declarations

### Changed
- chore(deps): Update devDependencies

## [1.2.0] - 2020-05-31

### Added
- feat(TypeScript): Add TypeScript support

## [1.1.10] - 2020-05-16

### Added
- tests(stryker): Add Stryker-mutator tests

### Changed
- chore(deps): Update devDependencies

## [1.1.9] - 2020-04-28

### Changed
- chore(deps): Allow node.js v14
- chore(deps): Update devDependencies

## [1.1.8] - 2020-04-09

### Changed
- chore(deps): Update devDependencies

## [1.1.7] - 2020-03-22
### Changed
- chore(deps): Update devDependencies

## [1.1.6] - 2020-02-19
### Changed
- chore(deps): Add Cypress ^4.0.0 to peerDependencies
- chore(test): Update Cypress to v4.0.2 in e2e tests
- chore(deps): Update eslint-plugin-react and husky devDependencies
- chore(test): Update react-scripts devDependency in e2e tests
- docs(readme): Fix typo

## [1.1.5] - 2020-02-01
### Changed
- Update devDependencies

## [1.1.4] - 2020-01-13
### Changed
- Use fixed versions in e2e tests dependencies

## [1.1.3] - 2020-01-13
### Changed
- Use fixed versions in dependencies

## [1.1.2] - 2020-01-11
### Changed
- Upgrade dependencies
- Disable temporarily Sonar as it is under maintenance

## [1.1.1] - 2019-12-28
### Changed
- Upgrade dependencies.
- Rename acceptance tests into e2e tests.
- Improve documentation examples.

### Added
- Add npm command for running e2e tests.
- Add e2e tests to check that examples works.

## [1.1.0] - 2019-10-27
### Added
- Add getLocalStorage command
- Add setLocalStorage command
- Add removeLocalStorage command
- Add acceptance tests

### Changed
- Improve documentation

## [1.0.0] - 2019-10-26
### Added
- Add saveLocalStorage command
- Add restoreLocalStorage command
- Add clearLocalStorageSnapshot command

## [1.0.0-alpha.1] - 2019-10-26
### Added
- Add package structure.
- Package still not functional.
- Reserve npm package name.



================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2019-2024 Javier Brea

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
[![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]

[![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]

[![NPM downloads][npm-downloads-image]][npm-downloads-url] [![License][license-image]][license-url]

# Cypress localStorage commands

Extends Cypress' cy commands with localStorage methods. Allows preserving localStorage between tests and spec files, and disabling localStorage.

## The problems

* You want to preserve localStorage between Cypress tests.
* You want to preserve localStorage between Cypress spec files.
* You want to disable localStorage to check error handling.

## This solution

This 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.

## Alternatives

As 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.__

## Installation

This module is distributed via npm which is bundled with node and should be installed as one of your project's devDependencies:

```bash
npm i --save-dev cypress-localstorage-commands
```

### Installing commands

`cypress-localstorage-commands` extends Cypress' cy commands.

At the top of your Cypress' support file (usually `cypress/support/e2e.js` for `e2e` testing type):

```javascript
import "cypress-localstorage-commands";
```

Read [Cypress configuration docs](https://docs.cypress.io/guides/references/configuration) for further info.

<details>
<summary><strong>Installing commands in Cypress <10.0</strong></summary>

Add this line to your project's `cypress/support/index.js`:

```js
import "cypress-localstorage-commands"
```

</details>

### Installing Node events

__⚠ 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.

In the `cypress.config.js` file:

```javascript
module.exports = {
  e2e: {
    setupNodeEvents(on, config) {
      require("cypress-localstorage-commands/plugin")(on, config);
      return config;
    },
  },
};
```

<details>
<summary><strong>Installing Node events in Cypress <10.0</strong></summary>

In the `cypress/plugins/index.js` file:

```javascript
module.exports = (on, config) => {
  require("cypress-localstorage-commands/plugin")(on, config);
  return config;
};
```

</details>

## Usage

### Commands

#### `cy.saveLocalStorage([snapshotName])`

Saves current localStorage values into an internal "snapshot".

* `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.

#### `cy.restoreLocalStorage([snapshotName])`

Restores localStorage to previously "snapshot" saved values. __

* `snapshotName` _(String)_: Optional. If provided, the localStorage will be restored using data from that specific snapshot.

#### `cy.clearLocalStorageSnapshot([snapshotName])`

Clears localStorage "snapshot" values, so previously saved values are cleaned.

* `snapshotName` _(String)_: Optional. If provided, only data from that specific snapshot will be cleared.

#### `cy.getLocalStorage(item)`

Gets localStorage item. Equivalent to `localStorage.getItem` in browser.

* `item` _(String)_: Item to get from `localStorage`.

#### `cy.setLocalStorage(item, value)`

Sets localStorage item. Equivalent to `localStorage.setItem` in browser.

* `item` _(String)_: Item to set value.
* `value` _(String)_: Value to be set.

#### `cy.removeLocalStorage(item)`

Removes localStorage item. Equivalent to `localStorage.removeItem` in browser.

* `item` _(String)_: Item to be removed.

#### `cy.disableLocalStorage(options)`

Disables localStorage. It produces localStorage methods to throw errors.

* `options` _(Object)_: Options to use when disabling `localStorage`.
  * `withError` _(Error)_: If provided, invocations to `localStorage` methods will throw this error.

### Preserving local storage between tests

Use `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._

> ⚠ 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.

### Examples

#### Cookies button example

Next 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)_

```js
describe("Accept cookies button", () => {
  const COOKIES_BUTTON = "#accept-cookies";

  before(() => {
    cy.clearLocalStorageSnapshot();
  });

  beforeEach(() => {
    cy.restoreLocalStorage();
    cy.visit("/");
  });

  afterEach(() => {
    cy.saveLocalStorage();
  });

  it("should be visible", () => {
    cy.get(COOKIES_BUTTON).should("be.visible");
  });

  it("should not be visible after clicked", () => {
    cy.get(COOKIES_BUTTON).click();
    cy.get(COOKIES_BUTTON).should("not.be.visible");
  });

  it("should not be visible after reloading", () => {
    cy.get(COOKIES_BUTTON).should("not.be.visible");
  });
});
```

> 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.

#### localStorage assertions

Based on the previous example, assertions could be added to check values of `localStorage`:

```js
describe("localStorage cookies-accepted item", () => {
  beforeEach(() => {
    cy.restoreLocalStorage();
    cy.visit("/");
  });

  afterEach(() => {
    cy.saveLocalStorage();
  });

  it("should be null first time page is visited", () => {
    cy.getLocalStorage("cookies-accepted").should("equal", null);
  });

  it("should be true after clicking cookies button", () => {
    cy.get("#accept-cookies").click();
    cy.getLocalStorage("cookies-accepted").should("equal", "true");
  });

  it("should be true after reloading", () => {
    cy.getLocalStorage("cookies-accepted").then(cookiesAccepted => {
      expect(cookiesAccepted).to.equal("true");
    });
  });
});
```

#### Named snapshots

Next example shows how named snapshots can be used to storage different states of `localStorage` and restore one or another depending of the test:

```js
describe("Accept cookies button", () => {
  const COOKIES_BUTTON = "#accept-cookies";

  before(() => {
    cy.clearLocalStorageSnapshot();
  });

  it("should be visible", () => {
    cy.visit("/");
    cy.get(COOKIES_BUTTON).should("be.visible");
    cy.saveLocalStorage("cookies-not-accepted");
  });

  it("should not exist after clicked", () => {
    cy.get(COOKIES_BUTTON).click();
    cy.get(COOKIES_BUTTON).should("not.exist");
    cy.saveLocalStorage("cookies-accepted");
  });

  it("should be visible when cookies are not accepted", () => {
    cy.restoreLocalStorage("cookies-not-accepted");
    cy.visit("/");
    cy.get(COOKIES_BUTTON).should("be.visible");
  });

  it("should not exist when cookies are accepted", () => {
    cy.restoreLocalStorage("cookies-accepted");
    cy.visit("/");
    cy.get(COOKIES_BUTTON).should("not.exist");
  });
});
```

### Disabling localStorage

Use `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.

Note that:

* Only pages loaded after calling this command will have `localStorage` disabled, so always use `cy.reload` or `cy.visit` after executing it.
* 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.
* 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"_

### Examples

#### Disabling localStorage in a single test

Based on previous "Accept cookies button" example, next tests could be added:

```js
//...
const LOCALSTORAGE_DISABLED_WARNING = "#localstorage-disabled-warning";
const LOCALSTORAGE_ERROR = "#localstorage-error";

//... should not be visible after clicked

it("should still be visible when reloading if localStorage is disabled", () => {
  cy.disableLocalStorage();
  cy.reload();
  cy.get(COOKIES_BUTTON).should("be.visible");
});

it("should display warning if localStorage is disabled", () => {
  cy.disableLocalStorage();
  cy.reload();
  cy.get(LOCALSTORAGE_DISABLED_WARNING).should("be.visible");
});

it("should display localStorage error message", () => {
  cy.disableLocalStorage();
  cy.reload();
  cy.get(LOCALSTORAGE_ERROR).should("have.text", "Error");
});

// ...should not be visible after reloading
```

#### Disabling localStorage in multiple tests

```js
describe("when localStorage is disabled", () => {
  beforeEach(() => {
    cy.disableLocalStorage({
      withError: new Error("Disabled by cypress-localstorage-commands"),
    });
    cy.visit("/");
  });

  it("should display localStorage warning", () => {
    cy.get("#localstorage-disabled-warning").should("be.visible");
  });

  it("should display localStorage error message", () => {
    cy.get("#localstorage-error").should("have.text", "Disabled by cypress-localstorage-commands");
  });

  it("should display accept-cookies button disabled", () => {
    cy.get("#accept-cookies").should("be.disabled");
  });
});
```

## Usage with TypeScript

For those writing [TypesScript tests in Cypress][cypress-typescript], this package includes TypeScript declarations.

Add "cypress-localstorage-commands" to the `types` property of the `tsconfig.json` file:

```json
{
  "compilerOptions": {
    "types": ["cypress", "cypress-localstorage-commands"]
  }
}
```

Or reference the package in the files using it:

```typescript
/// <reference types="cypress-localstorage-commands" />
```

## Contributing

Contributors are welcome.
Please read the [contributing guidelines](.github/CONTRIBUTING.md) and [code of conduct](.github/CODE_OF_CONDUCT.md).

## License

MIT, see [LICENSE](./LICENSE) for details.

[coveralls-image]: https://coveralls.io/repos/github/javierbrea/cypress-localstorage-commands/badge.svg
[coveralls-url]: https://coveralls.io/github/javierbrea/cypress-localstorage-commands
[build-image]: https://github.com/javierbrea/cypress-localstorage-commands/workflows/build/badge.svg?branch=master
[build-url]: https://github.com/javierbrea/cypress-localstorage-commands/actions?query=workflow%3Abuild+branch%3Amaster
[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
[mutation-url]: https://dashboard.stryker-mutator.io/reports/github.com/javierbrea/cypress-localstorage-commands/master
[last-commit-image]: https://img.shields.io/github/last-commit/javierbrea/cypress-localstorage-commands.svg
[last-commit-url]: https://github.com/javierbrea/cypress-localstorage-commands/commits
[license-image]: https://img.shields.io/npm/l/cypress-localstorage-commands.svg
[license-url]: https://github.com/javierbrea/cypress-localstorage-commands/blob/master/LICENSE
[npm-downloads-image]: https://img.shields.io/npm/dm/cypress-localstorage-commands.svg
[npm-downloads-url]: https://www.npmjs.com/package/cypress-localstorage-commands
[quality-gate-image]: https://sonarcloud.io/api/project_badges/measure?project=javierbrea_cypress-localstorage-commands&metric=alert_status
[quality-gate-url]: https://sonarcloud.io/dashboard?id=javierbrea_cypress-localstorage-commands
[release-image]: https://img.shields.io/github/release-date/javierbrea/cypress-localstorage-commands.svg
[release-url]: https://github.com/javierbrea/cypress-localstorage-commands/releases

[cypress-typescript]: https://docs.cypress.io/guides/tooling/typescript-support.html


================================================
FILE: cspell/missing.txt
================================================
Brea
commonmark
coverallsapp
javierbrea
Merthin
prelint
sonarcloud
sonarqube
sonarsource
Uninen


================================================
FILE: cspell.config.js
================================================
const { resolve } = require("node:path");

const DICTIONARIES_BASE_PATH = resolve(__dirname, "cspell");

module.exports = {
  // Version of the setting file.  Always 0.2
  version: "0.2",
  // Paths to be ignored
  ignorePaths: [
    "**/node_modules/**",
    ".husky/**",
    "**/pnpm-lock.yaml",
    "**/cspell/*.txt",
    "cspell.config.js",
    "**/.gitignore",
    "**/coverage/**",
    "**/dist/**",
    "test-e2e/app/build/**",
    "test-e2e/*/cypress/integration/**",
    "test-e2e/app/build/**",
    "test-e2e/cypress-typescript/cypress/support/cypress-localstorage-commands/**",
    "reports/**",
  ],
  caseSensitive: false,
  // Language - current active spelling language
  language: "en",
  // Dictionaries to be used
  dictionaryDefinitions: [
    {
      name: "missing",
      path: `${DICTIONARIES_BASE_PATH}/missing.txt`,
    },
  ],
  dictionaries: ["missing"],
  languageSettings: [
    {
      // In markdown files
      languageId: "markdown",
      // Exclude code blocks from spell checking
      ignoreRegExpList: ["/^\\s*```[\\s\\S]*?^\\s*```/gm"],
    },
  ],
  // The minimum length of a word before it is checked.
  minWordLength: 4,
  // 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"
  flagWords: ["hte"],
};


================================================
FILE: eslint.config.mjs
================================================
import json from "@eslint/json";
import markdown from "@eslint/markdown";
import prettier from "eslint-plugin-prettier";
import eslintPluginPrettierRecommended from "eslint-plugin-prettier/recommended";
import eslintConfigPrettier from "eslint-config-prettier";
import js from "@eslint/js";
import globals from "globals";
// eslint-disable-next-line import/no-unresolved
import typescriptParser from "@typescript-eslint/parser";
// eslint-disable-next-line import/no-unresolved
import typescriptEslintPlugin from "@typescript-eslint/eslint-plugin";
import pluginJest from "eslint-plugin-jest";
import importPlugin from "eslint-plugin-import";
// eslint-disable-next-line import/no-unresolved
import pluginCypress from "eslint-plugin-cypress/flat";
import reactPlugin from "eslint-plugin-react";

export default [
  {
    ignores: [
      "**/node_modules/**",
      ".husky/**",
      "dist/**",
      "test-e2e/*/cypress/integration/**",
      "test-e2e/app/build/**",
      "test-e2e/cypress-typescript/cypress/support/cypress-localstorage-commands/**",
      "reports/**",
    ],
  },
  {
    files: ["**/*.json"],
    language: "json/json",
    plugins: {
      json,
    },
    rules: {
      "json/no-duplicate-keys": "error",
      "json/no-empty-keys": "error",
    },
  },
  {
    files: ["**/*.md"],
    plugins: {
      markdown,
    },
    language: "markdown/commonmark",
    rules: {
      "markdown/no-html": [0],
    },
  },
  {
    files: [
      "**/*.js",
      "**/*.cjs",
      "**/*.mjs",
      "**/*.jsx",
      "**/*.ts",
      "**/*.tsx",
    ],
    plugins: {
      prettier,
      import: importPlugin,
    },
    languageOptions: {
      ecmaVersion: "latest",
      sourceType: "module",
      globals: {
        ...globals.node,
      },
    },
    rules: {
      ...importPlugin.flatConfigs.recommended.rules,
      ...js.configs.recommended.rules,
      ...eslintConfigPrettier.rules,
      ...eslintPluginPrettierRecommended.rules,
      camelcase: [2, { properties: "never" }],
      "no-console": [2, { allow: ["warn", "error"] }],
      "no-shadow": [2, { builtinGlobals: true, hoist: "all" }],
      "no-undef": [2],
      "no-unused-vars": [
        2,
        { vars: "all", args: "after-used", ignoreRestSiblings: false },
      ],
    },
  },
  {
    files: ["**/*.cjs"],
    languageOptions: {
      ecmaVersion: "latest",
      sourceType: "commonjs",
    },
  },
  {
    files: ["**/*.ts"],
    languageOptions: {
      parser: typescriptParser,
      parserOptions: {
        projectService: true,
      },
    },
    plugins: {
      "@typescript-eslint": typescriptEslintPlugin,
    },
    rules: {
      ...typescriptEslintPlugin.configs.recommended.rules,
    },
    settings: {
      "import/resolver": {
        typescript: {
          extensions: [".ts", ".tsx"],
          alwaysTryTypes: true,
        },
        node: true,
      },
    },
  },
  {
    files: ["**/plugin.d.ts"],
    languageOptions: {
      globals: {
        Cypress: "readonly",
      },
    },
  },
  {
    files: ["test/**/*.spec.js"],
    plugins: {
      jest: pluginJest,
    },
    ...pluginJest.configs["flat/recommended"],
    languageOptions: {
      globals: pluginJest.environments.globals.globals,
    },
    rules: {
      ...pluginJest.configs["flat/recommended"].rules,
      "jest/no-disabled-tests": "error",
      "jest/no-focused-tests": "error",
      "jest/no-identical-title": "error",
      "jest/prefer-to-have-length": "error",
      "jest/valid-expect": "error",
      "jest/prefer-strict-equal": [0],
      "jest/prefer-importing-jest-globals": [0],
      "jest/prefer-expect-assertions": [0],
      "jest/no-hooks": [0],
      "jest/prefer-called-with": [0],
      "jest/require-to-throw-message": [0],
    },
  },
  {
    files: ["test-e2e/app/src/**/*.js"],
    plugins: {
      react: reactPlugin,
    },
    ...reactPlugin.configs.flat.recommended,
    languageOptions: {
      ...reactPlugin.configs.flat.recommended.languageOptions,
      globals: {
        ...globals.browser,
      },
    },
    settings: {
      react: {
        pragma: "React",
        version: "^17.0.0",
      },
    },
    rules: {
      "react/jsx-uses-react": "error",
      "react/jsx-uses-vars": "error",
      "react/react-in-jsx-scope": "off",
    },
  },
  {
    files: ["**/*.cy.js", "**/*.cy.ts"],
    plugins: {
      cypress: pluginCypress,
    },
    ...pluginCypress.configs.recommended,
  },
  // TODO: Add config for cypress tests
];


================================================
FILE: index.d.ts
================================================
/// <reference types="cypress" />

declare namespace Cypress {
  interface Chainable {
    /**
     * Command to save current localStorage values into an internal "snapshot"
     * @param {string} snapshotName - Name of the snapshot
     * @example cy.saveLocalStorage()
     */
    saveLocalStorage(snapshotName?: string): Chainable<undefined>;

    /**
     * Command to restore localStorage to previously "snapshot" saved values
     * @param {string} snapshotName - Name of the snapshot
     * @example cy.restoreLocalStorage()
     */
    restoreLocalStorage(snapshotName?: string): Chainable<undefined>;

    /**
     * Command to clear localStorage "snapshot" values
     * @param {string} snapshotName - Name of the snapshot
     * @example cy.clearLocalStorageSnapshot()
     */
    clearLocalStorageSnapshot(snapshotName?: string): Chainable<undefined>;

    /**
     * Command to get localStorage item value
     * @param {string} itemKeyName - localStorage item to get
     * @example cy.getLocalStorage("cookies-accepted")
     */
    getLocalStorage(itemKeyName: string): Chainable<string | null>;

    /**
     * Command to set localStorage item value
     * @param {string} itemKeyName - localStorage item to set
     * @param {string} value - value to be set
     * @example cy.setLocalStorage("cookies-accepted", "true")
     */
    setLocalStorage(itemKeyName: string, value: string): Chainable<undefined>;

    /**
     * Command to remove localStorage item
     * @param {string} itemKeyName - localStorage item to remove
     * @example cy.removeLocalStorage("cookies-accepted")
     */
    removeLocalStorage(itemKeyName: string): Chainable<undefined>;

    /**
     * Command to disable localStorage
     * @param {object} options - Options for disabling localStorage
     * @example cy.disableLocalStorage()
     */
    disableLocalStorage(options?: { withError: Error }): Chainable<undefined>;
  }
}


================================================
FILE: index.js
================================================
/* global Cypress, cy, localStorage */

const { register } = require("./src/register");

register(Cypress, cy, localStorage);


================================================
FILE: jest.config.js
================================================
// For a detailed explanation regarding each configuration property, visit:
// https://jestjs.io/docs/en/configuration.html

module.exports = {
  // Automatically clear mock calls and instances between every test
  clearMocks: true,

  // Indicates whether the coverage information should be collected while executing the test
  collectCoverage: true,

  // An array of glob patterns indicating a set of files for which coverage information should be collected
  collectCoverageFrom: ["src/**"],

  // The directory where Jest should output its coverage files
  coverageDirectory: "coverage",

  // An object that configures minimum threshold enforcement for coverage results
  coverageThreshold: {
    global: {
      branches: 100,
      functions: 100,
      lines: 100,
      statements: 100,
    },
  },

  // The test environment that will be used for testing
  testEnvironment: "node",

  // The glob patterns Jest uses to detect test files
  testMatch: ["**/test/**/*.spec.js"],
};


================================================
FILE: package.json
================================================
{
  "name": "cypress-localstorage-commands",
  "version": "2.3.0",
  "description": "Extends Cypress' cy commands with localStorage methods. Allows preserving localStorage between tests",
  "keywords": [
    "cypress",
    "plugin",
    "local-storage",
    "localstorage",
    "methods",
    "utilities",
    "commands",
    "testing-tools",
    "testing",
    "persistence"
  ],
  "author": "Javier Brea",
  "license": "MIT",
  "repository": "https://github.com/javierbrea/cypress-localstorage-commands",
  "files": [
    "src",
    "index.d.ts",
    "plugin.js",
    "plugin.d.ts"
  ],
  "main": "index.js",
  "types": "index.d.ts",
  "scripts": {
    "cspell": "cspell . --quiet",
    "lint": "eslint .",
    "lint-staged": "lint-staged",
    "test": "jest",
    "test:ci": "pnpm run test:unit && pnpm run test:mutation && pnpm run test:e2e",
    "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",
    "test:e2e:cypress-9": "pnpm --filter cypress-9 test:ci",
    "test:e2e:cypress-9-no-plugin": "pnpm --filter cypress-9-no-plugin test:ci",
    "test:e2e:cypress-14": "pnpm --filter cypress-14 test:ci",
    "test:e2e:cypress-14-no-plugin": "pnpm --filter cypress-14-no-plugin test:ci",
    "test:e2e:cypress-latest": "pnpm --filter cypress-latest test:ci",
    "test:e2e:cypress-latest-no-plugin": "pnpm --filter cypress-latest-no-plugin test:ci",
    "test:e2e:cypress-typescript": "pnpm --filter cypress-typescript test:ci",
    "test:mutation": "stryker run",
    "test:unit": "pnpm run test",
    "tsc": "tsc",
    "prepare": "is-ci || husky install"
  },
  "peerDependencies": {
    "cypress": ">=2.1.0"
  },
  "devDependencies": {
    "@cypress/webpack-preprocessor": "6.0.4",
    "@eslint/js": "9.32.0",
    "@eslint/json": "0.13.1",
    "@eslint/markdown": "7.5.1",
    "@stryker-mutator/core": "9.6.0",
    "@stryker-mutator/jest-runner": "9.6.0",
    "@typescript-eslint/eslint-plugin": "8.57.0",
    "@typescript-eslint/parser": "8.57.0",
    "babel-loader": "10.1.1",
    "babel-plugin-module-resolver": "5.0.2",
    "cspell": "9.7.0",
    "cypress": "15.12.0",
    "eslint": "9.32.0",
    "eslint-config-prettier": "10.1.8",
    "eslint-import-resolver-typescript": "4.4.4",
    "eslint-plugin-cypress": "5.1.0",
    "eslint-plugin-import": "2.32.0",
    "eslint-plugin-jest": "29.15.0",
    "eslint-plugin-prettier": "5.5.5",
    "eslint-plugin-react": "7.37.5",
    "fs-extra": "11.3.4",
    "globals": "16.3.0",
    "husky": "9.1.7",
    "is-ci": "4.1.0",
    "jest": "30.3.0",
    "lint-staged": "16.4.0",
    "prettier": "3.8.1",
    "sinon": "21.0.2",
    "start-server-and-test": "2.1.5",
    "typescript": "5.9.3",
    "webpack": "5.105.4"
  },
  "lint-staged": {
    "**/*.js": "eslint",
    "**/*.ts": "eslint",
    "**/*.tsx": "eslint",
    "**/*.json": "eslint",
    "**/*.md": "eslint",
    "*.*": "cspell --no-must-find-files"
  },
  "engines": {
    "node": ">=14.0.0"
  },
  "packageManager": "pnpm@9.4.0"
}


================================================
FILE: plugin.d.ts
================================================
/// <reference types="cypress" />

/**
 * Installs cypress-localstorage-commands node events
 * @example plugin(on, config);
 * @param on Cypress plugin events
 * @param config Cypress plugin config options
 * @returns Cypress plugin config options
 */
declare function _exports(
  on: Cypress.PluginEvents,
  config: Cypress.PluginConfigOptions,
): Cypress.PluginConfigOptions;
export = _exports;


================================================
FILE: plugin.js
================================================
module.exports = require("./src/plugin");


================================================
FILE: pnpm-workspace.yaml
================================================
packages:
  - "."
  - "test-e2e/app"
  - "test-e2e/cypress-*"


================================================
FILE: renovate.json
================================================
{
  "extends": [
    "github>javierbrea/renovate-config"
  ],
  "packageRules": [
    {
      "matchPaths": ["test-e2e/cypress-9/package.json"],
      "matchPackageNames": ["cypress"],
      "allowedVersions": "9.x"
    },
    {
      "matchPaths": ["test-e2e/cypress-9-no-plugin/package.json"],
      "matchPackageNames": ["cypress"],
      "allowedVersions": "9.x"
    },
    {
      "matchPaths": ["test-e2e/cypress-latest/package.json"],
      "matchPackageNames": ["cypress"],
      "allowedVersions": "13.x"
    },
    {
      "matchPaths": ["test-e2e/cypress-latest-no-plugin/package.json"],
      "matchPackageNames": ["cypress"],
      "allowedVersions": "13.x"
    }
  ]
}


================================================
FILE: sonar-project.properties
================================================
sonar.organization=javierbrea
sonar.projectKey=javierbrea_cypress-localstorage-commands
sonar.projectVersion=2.3.0

sonar.javascript.file.suffixes=.js
sonar.sourceEncoding=UTF-8
sonar.exclusions=node_modules/**,test-e2e/react-app/node_modules/**
sonar.coverage.exclusions=test/**/*,index.js,plugin.js,stryker.conf.js,jest.config.js,test-e2e/**/*,cspell.config.js,eslint.config.mjs
sonar.cpd.exclusions=test/**/*,test-e2e/**/*
sonar.javascript.lcov.reportPaths=coverage/lcov.info
sonar.host.url=https://sonarcloud.io


================================================
FILE: src/LocalStorage.js
================================================
const {
  GET_SNAPSHOT_TASK,
  SET_SNAPSHOT_TASK,
  CLEAR_SNAPSHOT_TASK,
  NODE_EVENTS_INSTALLED,
} = require("./constants");

const LOCAL_STORAGE_METHODS = ["setItem", "getItem", "removeItem", "clear"];

function logDisabled(method) {
  return function () {
    this._cy.log(`localStorage.${method} is disabled`);
  };
}

function logDisabledMethodName(localStorageMethod) {
  return `_log${localStorageMethod}Disabled`;
}

class LocalStorage {
  static get cypressCommands() {
    return [
      "clearLocalStorageSnapshot",
      "saveLocalStorage",
      "restoreLocalStorage",
      "setLocalStorage",
      "getLocalStorage",
      "removeLocalStorage",
      "disableLocalStorage",
    ];
  }

  constructor(localStorage, cy, Cypress) {
    this._nodeEventsInstalled =
      (typeof Cypress.expose === "function"
        ? Cypress.expose(NODE_EVENTS_INSTALLED)
        : Cypress.env(NODE_EVENTS_INSTALLED)) === true;
    this._snapshot = {};
    this._namedSnapshots = {};
    this._cy = cy;
    this._localStorage = localStorage;

    LOCAL_STORAGE_METHODS.forEach((localStorageMethod) => {
      this[logDisabledMethodName(localStorageMethod)] =
        logDisabled(localStorageMethod).bind(this);
    });
  }

  _saveLocalStorageKeyToMemory(key, snapshotName) {
    if (snapshotName) {
      this._namedSnapshots[snapshotName][key] = this._localStorage.getItem(key);
    } else {
      this._snapshot[key] = this._localStorage.getItem(key);
    }
  }

  _saveLocalStorageToMemory(snapshotName) {
    Object.keys(this._localStorage).forEach((key) => {
      this._saveLocalStorageKeyToMemory(key, snapshotName);
    });
  }

  _clearMemorySnapshot(snapshotName) {
    if (snapshotName) {
      this._namedSnapshots[snapshotName] = {};
    } else {
      this._snapshot = {};
    }
  }

  _getSnapshotFromMemory(snapshotName) {
    return snapshotName ? this._namedSnapshots[snapshotName] : this._snapshot;
  }

  _restoreLocalStorageFromSnapshot(obj = {}) {
    Object.keys(obj).forEach((key) => {
      this._localStorage.setItem(key, obj[key]);
    });
  }

  _restoreLocalStorageFromMemory(snapshotName) {
    this._restoreLocalStorageFromSnapshot(
      this._getSnapshotFromMemory(snapshotName),
    );
  }

  _copySnapshotFromMemoryToNode(snapshotName) {
    if (this._nodeEventsInstalled) {
      return this._cy.task(SET_SNAPSHOT_TASK, {
        name: snapshotName,
        snapshot: this._getSnapshotFromMemory(snapshotName),
      });
    }
  }

  _clearNodeSnapshot(snapshotName) {
    if (this._nodeEventsInstalled) {
      return this._cy.task(CLEAR_SNAPSHOT_TASK, snapshotName);
    }
  }

  _restoreLocalStorageFromNode(snapshotName) {
    return this._cy.task(GET_SNAPSHOT_TASK, snapshotName).then((snapshot) => {
      this._restoreLocalStorageFromSnapshot(snapshot);
    });
  }

  clearLocalStorageSnapshot(snapshotName) {
    this._clearMemorySnapshot(snapshotName);
    return this._clearNodeSnapshot(snapshotName);
  }

  saveLocalStorage(snapshotName) {
    if (!this._localStorage.getItem.wrappedMethod) {
      this.clearLocalStorageSnapshot(snapshotName);
      this._saveLocalStorageToMemory(snapshotName);
      return this._copySnapshotFromMemoryToNode(snapshotName);
    }
  }

  restoreLocalStorage(snapshotName) {
    this._localStorage.clear();
    if (this._nodeEventsInstalled) {
      return this._restoreLocalStorageFromNode(snapshotName);
    } else {
      this._restoreLocalStorageFromMemory(snapshotName);
    }
  }

  getLocalStorage(key) {
    return this._localStorage.getItem(key);
  }

  setLocalStorage(key, value) {
    return this._localStorage.setItem(key, value);
  }

  removeLocalStorage(key) {
    return this._localStorage.removeItem(key);
  }

  disableLocalStorage(options = {}) {
    this._cy.on("window:before:load", (win) => {
      if (
        win.localStorage &&
        !win.localStorage[LOCAL_STORAGE_METHODS[0]].wrappedMethod &&
        !this._localStorage[LOCAL_STORAGE_METHODS[0]].wrappedMethod
      ) {
        LOCAL_STORAGE_METHODS.forEach((localStorageMethod) => {
          this._cy
            .stub(this._localStorage, localStorageMethod)
            .callsFake(this[logDisabledMethodName(localStorageMethod)]);
          this._cy
            .stub(win.localStorage, localStorageMethod)
            .throws(options.withError);
        });
      }
    });
  }
}

module.exports = LocalStorage;


================================================
FILE: src/constants.js
================================================
const GET_SNAPSHOT_TASK = "cypressLocalStorageGetSnapshot";
const SET_SNAPSHOT_TASK = "cypressLocalStorageSetSnapshot";
const CLEAR_SNAPSHOT_TASK = "cypressLocalStorageClearSnapshot";
const NODE_EVENTS_INSTALLED = "LOCALSTORAGE_NODE_EVENTS_INSTALLED";

module.exports = {
  GET_SNAPSHOT_TASK,
  SET_SNAPSHOT_TASK,
  CLEAR_SNAPSHOT_TASK,
  NODE_EVENTS_INSTALLED,
};


================================================
FILE: src/plugin.js
================================================
const {
  GET_SNAPSHOT_TASK,
  SET_SNAPSHOT_TASK,
  CLEAR_SNAPSHOT_TASK,
  NODE_EVENTS_INSTALLED,
} = require("./constants");

const plugin = (on, config) => {
  const namedSnapshots = {};
  let globalSnapshot = {};

  if (config.expose === undefined) {
    config.env[NODE_EVENTS_INSTALLED] = true;
  } else {
    config.expose[NODE_EVENTS_INSTALLED] = true;
  }

  // Create cypress-local-storage-commands tasks
  on("task", {
    [GET_SNAPSHOT_TASK]: function (name) {
      return name ? namedSnapshots[name] || {} : globalSnapshot;
    },
    [SET_SNAPSHOT_TASK]: function ({ name, snapshot }) {
      if (name) {
        namedSnapshots[name] = snapshot;
      } else {
        globalSnapshot = snapshot;
      }
      return null;
    },
    [CLEAR_SNAPSHOT_TASK]: function (name) {
      if (name) {
        namedSnapshots[name] = {};
      } else {
        globalSnapshot = {};
      }
      return null;
    },
  });

  return config;
};

module.exports = plugin;


================================================
FILE: src/register.js
================================================
const LocalStorage = require("./LocalStorage");

const register = (Cypress, cy, localStorage) => {
  const localStorageCommands = new LocalStorage(localStorage, cy, Cypress);

  // Register commands
  LocalStorage.cypressCommands.forEach((commandName) => {
    Cypress.Commands.add(
      commandName,
      localStorageCommands[commandName].bind(localStorageCommands),
    );
  });
};

module.exports = {
  register,
};


================================================
FILE: stryker.conf.js
================================================
const BRANCH_NAME = process.env.BRANCH_NAME;
const STRYKER_DASHBOARD_API_KEY = process.env.STRYKER_DASHBOARD_API_KEY;

const BASE_CONFIG = {
  ignorePatterns: ["**", "!*.js", "!src/**/*.js", "!test/**/*.js"],
  packageManager: "npm",
  thresholds: {
    high: 80,
    low: 60,
    break: 80,
  },
  reporters: ["html", "clear-text", "progress", "dashboard"],
  testRunner: "jest",
  coverageAnalysis: "off",
  plugins: ["@stryker-mutator/jest-runner"],
};

const config = {
  ...BASE_CONFIG,
  dashboard:
    BRANCH_NAME && STRYKER_DASHBOARD_API_KEY
      ? {
          project: "github.com/javierbrea/cypress-localstorage-commands",
          version: BRANCH_NAME,
        }
      : undefined,
};

module.exports = config;


================================================
FILE: test/Cy.mock.js
================================================
const sinon = require("sinon");

const doNothing = () => {
  // do nothing
};

class Cy {
  constructor() {
    this._sandbox = sinon.createSandbox();

    this._windowMock = {
      localStorage: {
        setItem: doNothing,
        getItem: doNothing,
        removeItem: doNothing,
        clear: doNothing,
      },
    };

    this._stubs = {
      on: this._sandbox.stub().callsFake((_eventName, callback) => {
        this._callback = callback;
      }),
      log: this._sandbox.stub(),
      stub: this._sandbox.stub,
      task: this._sandbox.stub().resolves(),
    };
  }

  get stubs() {
    return this._stubs;
  }

  restore() {
    this._sandbox.restore();
  }

  reset() {
    this._sandbox.reset();
  }

  loadWindow() {
    this._callback(this._windowMock);
  }

  get window() {
    return this._windowMock;
  }
}

module.exports = Cy;


================================================
FILE: test/Cypress.mock.js
================================================
const sinon = require("sinon");

const Mock = class Mock {
  constructor() {
    this._sandbox = sinon.createSandbox();

    this._stubs = {
      Commands: {
        add: this._sandbox.stub(),
      },
      env: this._sandbox.stub(),
      expose: this._sandbox.stub(),
    };
  }

  get stubs() {
    return this._stubs;
  }

  restore() {
    this._sandbox.restore();
  }
};

module.exports = Mock;


================================================
FILE: test/LocalStorage.mock.js
================================================
const sinon = require("sinon");

const LOCALSTORAGE_METHODS = new Set([
  "getItem",
  "setItem",
  "removeItem",
  "clear",
]);

const Mock = class Mock {
  constructor() {
    this._sandbox = sinon.createSandbox();

    this._stubs = {
      getItem: this._sandbox.stub().callsFake((key) => {
        return this._stubs[key];
      }),
      setItem: this._sandbox.stub().callsFake((key, value) => {
        if (!LOCALSTORAGE_METHODS.has(key)) {
          this._stubs[key] = value;
        }
      }),
      removeItem: this._sandbox.stub().callsFake((key) => {
        delete this._stubs[key];
      }),
      clear: this._sandbox.stub().callsFake(() => {
        Object.keys(this._stubs).forEach((key) => {
          if (!LOCALSTORAGE_METHODS.has(key)) {
            delete this._stubs[key];
          }
        });
      }),
    };
  }

  get stubs() {
    return this._stubs;
  }

  restore() {
    this._sandbox.restore();
  }

  reset() {
    this._sandbox.reset();
  }
};

module.exports = Mock;


================================================
FILE: test/LocalStorage.spec.js
================================================
const LocalStorageMock = require("./LocalStorage.mock");
const CyMock = require("./Cy.mock");
const CypressMock = require("./Cypress.mock");
const LocalStorage = require("../src/LocalStorage");

describe("LocalStorage", () => {
  let windowLocalStorageMock;
  let localStorageMock;
  let localStorage;
  let cyMock;
  let cypressMock;

  beforeAll(() => {
    cyMock = new CyMock();
    // Ensure that tasks are not called (plugin must be disabled in these tests)
    cyMock.stubs.task.throws();
    cypressMock = new CypressMock();
    localStorageMock = new LocalStorageMock();
    localStorage = new LocalStorage(
      localStorageMock.stubs,
      cyMock.stubs,
      cypressMock.stubs,
    );
  });

  afterAll(() => {
    cyMock.restore();
    localStorageMock.restore();
  });

  describe("LocalStorage", () => {
    describe("save and restore methods", () => {
      it("should restore values that localStorage had when save method was called", () => {
        expect.assertions(2);
        localStorageMock.stubs.setItem("foo", "foo-value");
        localStorageMock.stubs.setItem("var", "var-value");
        localStorage.saveLocalStorage();
        localStorageMock.stubs.setItem("foo", "foo-new-value");
        expect(localStorageMock.stubs.getItem("foo")).toEqual("foo-new-value");
        localStorage.restoreLocalStorage();
        expect(localStorageMock.stubs.getItem("foo")).toEqual("foo-value");
      });

      it("should restore values after calling localStorage clear", () => {
        expect.assertions(2);
        localStorageMock.stubs.clear();
        expect(localStorageMock.stubs.getItem("var")).toEqual(undefined);
        localStorage.restoreLocalStorage();
        expect(localStorageMock.stubs.getItem("var")).toEqual("var-value");
      });

      it("should restore new values if Save is called again", () => {
        expect.assertions(2);
        localStorageMock.stubs.setItem("foo", "foo-new-value");
        localStorageMock.stubs.removeItem("var");
        localStorage.saveLocalStorage();
        localStorageMock.stubs.setItem("foo", "foo-another-new-value");
        localStorageMock.stubs.setItem("var", "foo-var-value");
        localStorage.restoreLocalStorage();
        expect(localStorageMock.stubs.getItem("foo")).toEqual("foo-new-value");
        expect(localStorageMock.stubs.getItem("var")).toEqual(undefined);
      });
    });

    describe("Clear method", () => {
      it("should clear values in localStorage snapshot, but maintain localStorage values", () => {
        expect.assertions(4);
        localStorageMock.stubs.setItem("var", "foo-var-value");
        localStorage.clearLocalStorageSnapshot();
        expect(localStorageMock.stubs.getItem("foo")).toEqual("foo-new-value");
        expect(localStorageMock.stubs.getItem("var")).toEqual("foo-var-value");
        localStorage.restoreLocalStorage();
        expect(localStorageMock.stubs.getItem("foo")).toEqual(undefined);
        expect(localStorageMock.stubs.getItem("var")).toEqual(undefined);
      });
    });
  });

  describe("LocalStorage named snapshots", () => {
    describe("save and restore methods", () => {
      it("should restore values that localStorage had when save method was called", () => {
        expect.assertions(3);
        localStorageMock.stubs.setItem("foo", "foo-value");
        localStorageMock.stubs.setItem("var", "var-value");
        localStorage.saveLocalStorage("first");
        localStorageMock.stubs.setItem("foo", "foo-new-value");
        localStorage.saveLocalStorage("second");
        expect(localStorageMock.stubs.getItem("foo")).toEqual("foo-new-value");
        localStorage.restoreLocalStorage("first");
        expect(localStorageMock.stubs.getItem("foo")).toEqual("foo-value");
        localStorage.restoreLocalStorage("second");
        expect(localStorageMock.stubs.getItem("foo")).toEqual("foo-new-value");
      });

      it("should clear whole localStorage if snapshot to restore does not exists", () => {
        localStorage.restoreLocalStorage("fourth");
        expect(localStorageMock.stubs.getItem("foo")).toEqual(undefined);
        expect(localStorageMock.stubs.getItem("var")).toEqual(undefined);
      });
    });

    describe("Clear method", () => {
      it("should clear values in localStorage snapshot, but maintain localStorage values", () => {
        expect.assertions(4);
        localStorage.restoreLocalStorage("second");
        localStorageMock.stubs.setItem("var", "foo-var-value");
        localStorage.clearLocalStorageSnapshot("second");
        expect(localStorageMock.stubs.getItem("foo")).toEqual("foo-new-value");
        expect(localStorageMock.stubs.getItem("var")).toEqual("foo-var-value");
        localStorage.restoreLocalStorage("second");
        expect(localStorageMock.stubs.getItem("foo")).toEqual(undefined);
        expect(localStorageMock.stubs.getItem("var")).toEqual(undefined);
      });

      it("should not clear values from other snapshot", () => {
        localStorage.restoreLocalStorage("first");
        expect(localStorageMock.stubs.getItem("foo")).toEqual("foo-value");
        expect(localStorageMock.stubs.getItem("var")).toEqual("var-value");
      });
    });
  });

  describe("setLocalStorage method", () => {
    it("should set values in localStorage", () => {
      expect.assertions(2);
      localStorage.setLocalStorage("foo", "foo-value");
      localStorage.setLocalStorage("var", "var-value");
      expect(localStorageMock.stubs.getItem("foo")).toEqual("foo-value");
      expect(localStorageMock.stubs.getItem("var")).toEqual("var-value");
    });

    it("should not have set values in localStorage snapshot", () => {
      expect.assertions(2);
      localStorage.restoreLocalStorage();
      expect(localStorageMock.stubs.getItem("foo")).toEqual(undefined);
      expect(localStorageMock.stubs.getItem("var")).toEqual(undefined);
    });
  });

  describe("getLocalStorage method", () => {
    it("should get localStorage items", () => {
      expect.assertions(2);
      localStorage.setLocalStorage("foo", "foo-value");
      localStorage.setLocalStorage("var", "var-value");
      expect(localStorage.getLocalStorage("foo")).toEqual("foo-value");
      expect(localStorage.getLocalStorage("var")).toEqual("var-value");
    });
  });

  describe("removeLocalStorage", () => {
    it("should remove local storage items", () => {
      expect.assertions(2);
      localStorage.saveLocalStorage();
      localStorage.removeLocalStorage("foo");
      expect(localStorage.getLocalStorage("foo")).toEqual(undefined);
      expect(localStorage.getLocalStorage("var")).toEqual("var-value");
    });

    it("should not remove local storage items from localstorage snapshot", () => {
      expect.assertions(2);
      localStorage.restoreLocalStorage();
      expect(localStorage.getLocalStorage("foo")).toEqual("foo-value");
      expect(localStorage.getLocalStorage("var")).toEqual("var-value");
    });
  });

  describe("LocalStorage when memory is cleaned", () => {
    describe("save and restore methods", () => {
      it("should not restore values that localStorage had when save method was called", () => {
        expect.assertions(2);
        localStorageMock.stubs.setItem("foo", "foo-value");
        localStorageMock.stubs.setItem("var", "var-value");
        localStorage.saveLocalStorage();
        localStorageMock.stubs.setItem("foo", "foo-new-value");
        expect(localStorageMock.stubs.getItem("foo")).toEqual("foo-new-value");
        localStorage._namedSnapshots = {};
        localStorage._snapshot = {};
        localStorage.restoreLocalStorage();
        expect(localStorageMock.stubs.getItem("foo")).toEqual(undefined);
      });

      it("should not restore values after calling localStorage clear", () => {
        expect.assertions(2);
        localStorageMock.stubs.clear();
        expect(localStorageMock.stubs.getItem("var")).toEqual(undefined);
        localStorage.restoreLocalStorage();
        expect(localStorageMock.stubs.getItem("var")).toEqual(undefined);
      });

      it("should not restore new values if Save is called again", () => {
        expect.assertions(2);
        localStorageMock.stubs.setItem("foo", "foo-new-value");
        localStorageMock.stubs.removeItem("var");
        localStorage.saveLocalStorage();
        localStorageMock.stubs.setItem("foo", "foo-another-new-value");
        localStorageMock.stubs.setItem("var", "foo-var-value");
        localStorage._namedSnapshots = {};
        localStorage._snapshot = {};
        localStorage.restoreLocalStorage();
        expect(localStorageMock.stubs.getItem("foo")).toEqual(undefined);
        expect(localStorageMock.stubs.getItem("var")).toEqual(undefined);
      });
    });
  });

  describe("disableLocalStorage", () => {
    beforeEach(() => {
      windowLocalStorageMock = new CyMock();
      cyMock = new CyMock();
      cypressMock = new CypressMock();
      localStorage = new LocalStorage(
        windowLocalStorageMock.window.localStorage,
        cyMock.stubs,
        cypressMock.stubs,
      );
    });

    afterEach(() => {
      windowLocalStorageMock.restore();
    });

    it("should do nothing if page is not reloaded", () => {
      expect.assertions(3);
      localStorage.disableLocalStorage();
      expect(() => cyMock.window.localStorage.setItem()).not.toThrow();
      expect(() => cyMock.window.localStorage.getItem()).not.toThrow();
      expect(() => cyMock.window.localStorage.removeItem()).not.toThrow();
    });

    it("should use Cypress window:before:load event to create stubs", () => {
      localStorage.disableLocalStorage();
      expect(cyMock.stubs.on.getCall(0).args[0]).toEqual("window:before:load");
    });

    it("should make localStorage methods to throw after reloading page", () => {
      expect.assertions(3);
      localStorage.disableLocalStorage();
      cyMock.loadWindow();
      expect(() => cyMock.window.localStorage.setItem()).toThrow();
      expect(() => cyMock.window.localStorage.getItem()).toThrow();
      expect(() => cyMock.window.localStorage.removeItem()).toThrow();
    });

    it("should make cy.setLocalStorage command to log after reloading page", () => {
      expect.assertions(1);
      localStorage.disableLocalStorage();
      cyMock.loadWindow();
      localStorage.setLocalStorage("foo", "foo");
      expect(
        cyMock.stubs.log.calledWith("localStorage.setItem is disabled"),
      ).toEqual(true);
    });

    it("should make cy.getLocalStorage command to log after reloading page", () => {
      expect.assertions(1);
      localStorage.disableLocalStorage();
      cyMock.loadWindow();
      localStorage.getLocalStorage("foo");
      expect(
        cyMock.stubs.log.calledWith("localStorage.getItem is disabled"),
      ).toEqual(true);
    });

    it("should make cy.removeLocalStorage command to log after reloading page", () => {
      expect.assertions(1);
      localStorage.disableLocalStorage();
      cyMock.loadWindow();
      localStorage.removeLocalStorage("foo");
      expect(
        cyMock.stubs.log.calledWith("localStorage.removeItem is disabled"),
      ).toEqual(true);
    });

    it("should make cy.restoreLocalStorage command to log after reloading page", () => {
      expect.assertions(1);
      localStorage.disableLocalStorage();
      cyMock.loadWindow();
      localStorage.restoreLocalStorage();
      expect(
        cyMock.stubs.log.calledWith("localStorage.clear is disabled"),
      ).toEqual(true);
    });

    it("should make cy.saveLocalStorage command to do nothing", () => {
      expect.assertions(1);
      localStorage.disableLocalStorage();
      cyMock.loadWindow();
      localStorage.saveLocalStorage();
      expect(
        windowLocalStorageMock.window.localStorage.getItem.callCount,
      ).toEqual(0);
    });

    it("should do nothing if window.localStorage is not available", () => {
      cyMock.window.localStorage = null;
      localStorage.disableLocalStorage();
      cyMock.loadWindow();
      localStorage.setLocalStorage("foo", "foo");
      expect(cyMock.stubs.log.callCount).toEqual(0);
    });

    it("should work when reloading page multiple times", () => {
      expect.assertions(3);
      localStorage.disableLocalStorage();
      cyMock.loadWindow();
      cyMock.loadWindow();
      cyMock.loadWindow();
      expect(() => cyMock.window.localStorage.setItem()).toThrow();
      expect(() => cyMock.window.localStorage.getItem()).toThrow();
      expect(() => cyMock.window.localStorage.removeItem()).toThrow();
    });

    it("should work when called multiple times", () => {
      expect.assertions(3);
      localStorage.disableLocalStorage();
      cyMock.loadWindow();
      localStorage.disableLocalStorage();
      localStorage.disableLocalStorage();
      cyMock.loadWindow();
      expect(() => cyMock.window.localStorage.setItem()).toThrow();
      expect(() => cyMock.window.localStorage.getItem()).toThrow();
      expect(() => cyMock.window.localStorage.removeItem()).toThrow();
    });

    it("should throw error provided in the 'withError' option", () => {
      expect.assertions(3);
      const error = new Error("foo");
      localStorage.disableLocalStorage({
        withError: error,
      });
      cyMock.loadWindow();
      expect(() => cyMock.window.localStorage.setItem()).toThrow(error);
      expect(() => cyMock.window.localStorage.getItem()).toThrow(error);
      expect(() => cyMock.window.localStorage.removeItem()).toThrow(error);
    });
  });
});


================================================
FILE: test/LocalStorageNode.spec.js
================================================
const LocalStorageMock = require("./LocalStorage.mock");
const CyMock = require("./Cy.mock");
const CypressMock = require("./Cypress.mock");
const LocalStorage = require("../src/LocalStorage");
const plugin = require("../src/plugin");

describe("LocalStorage with node events", () => {
  let localStorageMock;
  let localStorage;
  let cyMock;
  let cypressMock;
  let cypressTasks;
  let config;

  const setupTest = (useExpose) => {
    cyMock = new CyMock();
    cypressMock = new CypressMock();
    config = useExpose ? { expose: {} } : { env: {} };

    cypressTasks = {};

    plugin((cyEvent, tasks) => {
      if (cyEvent === "task") {
        Object.keys(tasks).forEach((taskName) => {
          cypressTasks[taskName] = tasks[taskName];
        });
      }
    }, config);

    cyMock.stubs.task.callsFake((taskName, arg) => {
      if (!taskName) {
        throw new Error("Task name is required");
      }
      return new Promise((resolve, reject) => {
        const result = cypressTasks[taskName](arg);
        if (result === undefined) {
          reject(new Error("Task did not return a value"));
        }
        resolve(result);
      });
    });

    if (useExpose) {
      cypressMock.stubs.expose.callsFake((envVarName) => {
        if (!envVarName) {
          throw new Error("Env var name is required");
        }
        return config.expose[envVarName];
      });
    } else {
      cypressMock.stubs.env.callsFake((envVarName) => {
        if (!envVarName) {
          throw new Error("Env var name is required");
        }
        return config.env[envVarName];
      });
      // Mock expose to be undefined to simulate older Cypress versions
      cypressMock.stubs.expose = undefined;
    }

    localStorageMock = new LocalStorageMock();
    localStorage = new LocalStorage(
      localStorageMock.stubs,
      cyMock.stubs,
      cypressMock.stubs,
    );
  };

  afterEach(() => {
    cyMock.restore();
    localStorageMock.restore();
  });

  describe("when using Cypress.env (Cypress < 15.10.0)", () => {
    beforeEach(() => {
      setupTest(false);
    });

    it("should configure and read node events status correctly", () => {
      expect(config.env.LOCALSTORAGE_NODE_EVENTS_INSTALLED).toEqual(true);
      expect(localStorage._nodeEventsInstalled).toEqual(true);
    });
  });

  describe("when using Cypress.expose (Cypress >= 15.10.0)", () => {
    beforeEach(() => {
      setupTest(true);
    });

    it("should configure and read node events status correctly", () => {
      expect(config.expose.LOCALSTORAGE_NODE_EVENTS_INSTALLED).toEqual(true);
      expect(localStorage._nodeEventsInstalled).toEqual(true);
    });
  });

  describe("LocalStorage", () => {
    beforeEach(() => {
      setupTest(false); // Can use either for standard testing
      // clear memory to ensure that plugin is working
      localStorage._namedSnapshots = {};
      localStorage._snapshot = {};
    });

    describe("save and restore methods", () => {
      it("should restore values that localStorage had when save method was called", async () => {
        expect.assertions(2);
        localStorageMock.stubs.setItem("foo", "foo-value");
        localStorageMock.stubs.setItem("var", "var-value");
        await localStorage.saveLocalStorage();
        localStorageMock.stubs.setItem("foo", "foo-new-value");
        expect(localStorageMock.stubs.getItem("foo")).toEqual("foo-new-value");
        await localStorage.restoreLocalStorage();
        expect(localStorageMock.stubs.getItem("foo")).toEqual("foo-value");
      });

      it("should restore values from node snapshot when memory snapshot is empty", async () => {
        expect.assertions(1);
        localStorageMock.stubs.setItem("foo", "foo-value");
        await localStorage.saveLocalStorage();
        localStorageMock.stubs.clear();
        localStorage._snapshot = {};
        localStorage._namedSnapshots = {};
        await localStorage.restoreLocalStorage();
        expect(localStorageMock.stubs.getItem("foo")).toEqual("foo-value");
      });

      it("should restore values after calling localStorage clear", async () => {
        expect.assertions(2);
        localStorageMock.stubs.setItem("var", "var-value");
        await localStorage.saveLocalStorage();
        localStorageMock.stubs.clear();
        expect(localStorageMock.stubs.getItem("var")).toEqual(undefined);
        await localStorage.restoreLocalStorage();
        expect(localStorageMock.stubs.getItem("var")).toEqual("var-value");
      });

      it("should restore new values if Save is called again", async () => {
        expect.assertions(2);
        localStorageMock.stubs.setItem("foo", "foo-new-value");
        localStorageMock.stubs.removeItem("var");
        await localStorage.saveLocalStorage();
        localStorageMock.stubs.setItem("foo", "foo-another-new-value");
        localStorageMock.stubs.setItem("var", "foo-var-value");
        await localStorage.restoreLocalStorage();
        expect(localStorageMock.stubs.getItem("foo")).toEqual("foo-new-value");
        expect(localStorageMock.stubs.getItem("var")).toEqual(undefined);
      });
    });

    describe("Clear method", () => {
      it("should clear values in localStorage snapshot, but maintain localStorage values", async () => {
        expect.assertions(4);
        localStorageMock.stubs.setItem("foo", "foo-new-value");
        localStorageMock.stubs.setItem("var", "foo-var-value");
        await localStorage.saveLocalStorage();
        await localStorage.clearLocalStorageSnapshot();
        expect(localStorageMock.stubs.getItem("foo")).toEqual("foo-new-value");
        expect(localStorageMock.stubs.getItem("var")).toEqual("foo-var-value");
        await localStorage.restoreLocalStorage();
        expect(localStorageMock.stubs.getItem("foo")).toEqual(undefined);
        expect(localStorageMock.stubs.getItem("var")).toEqual(undefined);
      });
    });
  });

  describe("LocalStorage named snapshots", () => {
    beforeEach(() => {
      setupTest(false);
      localStorage._namedSnapshots = {};
      localStorage._snapshot = {};
    });
    describe("save and restore methods", () => {
      it("should restore values that localStorage had when save method was called", async () => {
        expect.assertions(3);
        localStorageMock.stubs.setItem("foo", "foo-value");
        localStorageMock.stubs.setItem("var", "var-value");
        await localStorage.saveLocalStorage("first");
        localStorageMock.stubs.setItem("foo", "foo-new-value");
        await localStorage.saveLocalStorage("second");
        expect(localStorageMock.stubs.getItem("foo")).toEqual("foo-new-value");
        await localStorage.restoreLocalStorage("first");
        expect(localStorageMock.stubs.getItem("foo")).toEqual("foo-value");
        await localStorage.restoreLocalStorage("second");
        expect(localStorageMock.stubs.getItem("foo")).toEqual("foo-new-value");
      });

      it("should clear whole localStorage if snapshot to restore does not exists", async () => {
        await localStorage.restoreLocalStorage("fourth");
        expect(localStorageMock.stubs.getItem("foo")).toEqual(undefined);
        expect(localStorageMock.stubs.getItem("var")).toEqual(undefined);
      });
    });

    describe("Clear method", () => {
      it("should clear values in localStorage snapshot, but maintain localStorage values", async () => {
        expect.assertions(4);
        localStorageMock.stubs.setItem("foo", "foo-new-value");
        localStorageMock.stubs.setItem("var", "foo-var-value");
        await localStorage.saveLocalStorage("second");
        await localStorage.restoreLocalStorage("second");
        localStorageMock.stubs.setItem("var", "foo-var-value");
        await localStorage.clearLocalStorageSnapshot("second");
        expect(localStorageMock.stubs.getItem("foo")).toEqual("foo-new-value");
        expect(localStorageMock.stubs.getItem("var")).toEqual("foo-var-value");
        await localStorage.restoreLocalStorage("second");
        expect(localStorageMock.stubs.getItem("foo")).toEqual(undefined);
        expect(localStorageMock.stubs.getItem("var")).toEqual(undefined);
      });

      it("should not clear values from other snapshot", async () => {
        localStorageMock.stubs.setItem("foo", "foo-value");
        localStorageMock.stubs.setItem("var", "var-value");
        await localStorage.saveLocalStorage("first");
        await localStorage.restoreLocalStorage("first");
        expect(localStorageMock.stubs.getItem("foo")).toEqual("foo-value");
        expect(localStorageMock.stubs.getItem("var")).toEqual("var-value");
      });
    });
  });

  describe("setLocalStorage method", () => {
    beforeEach(() => {
      setupTest(false);
      localStorage._namedSnapshots = {};
      localStorage._snapshot = {};
    });
    it("should set values in localStorage", async () => {
      expect.assertions(2);
      await localStorage.setLocalStorage("foo", "foo-value");
      await localStorage.setLocalStorage("var", "var-value");
      expect(localStorageMock.stubs.getItem("foo")).toEqual("foo-value");
      expect(localStorageMock.stubs.getItem("var")).toEqual("var-value");
    });

    it("should not have set values in localStorage snapshot", async () => {
      expect.assertions(2);
      await localStorage.restoreLocalStorage();
      expect(localStorageMock.stubs.getItem("foo")).toEqual(undefined);
      expect(localStorageMock.stubs.getItem("var")).toEqual(undefined);
    });
  });
});


================================================
FILE: test/register.spec.js
================================================
const LocalStorageMock = require("./LocalStorage.mock");
const CypressMock = require("./Cypress.mock");

const LocalStorage = require("../src/LocalStorage");
const { register } = require("../src/register");

describe("register", () => {
  let cypressMock;
  let localStorageMock;

  beforeEach(() => {
    localStorageMock = new LocalStorageMock();
    cypressMock = new CypressMock();
    register(cypressMock.stubs, localStorageMock.stubs);
  });

  afterEach(() => {
    localStorageMock.restore();
    cypressMock.restore();
  });

  describe("methods", () => {
    it("should register all LocalStorage public methods as commands on Cypress", () => {
      expect(cypressMock.stubs.Commands.add.callCount).toEqual(
        LocalStorage.cypressCommands.length,
      );
    });

    it("should register clearLocalStorageSnapshot method", () => {
      expect(
        cypressMock.stubs.Commands.add.calledWith("clearLocalStorageSnapshot"),
      ).toBe(true);
    });

    it("should register saveLocalStorage method", () => {
      expect(
        cypressMock.stubs.Commands.add.calledWith("saveLocalStorage"),
      ).toBe(true);
    });

    it("should register restoreLocalStorage method", () => {
      expect(
        cypressMock.stubs.Commands.add.calledWith("restoreLocalStorage"),
      ).toBe(true);
    });
  });
});


================================================
FILE: test-e2e/app/.gitignore
================================================
# See https://help.github.com/ignore-files/ for more about ignoring files.

#environment variables
#.env

# dependencies
/node_modules

#build
/build

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*

# ides
.idea
.vs

# caches
.eslintcache


================================================
FILE: test-e2e/app/package.json
================================================
{
  "name": "app",
  "private": true,
  "dependencies": {
    "@data-provider/browser-storage": "4.0.0",
    "@data-provider/core": "4.0.0",
    "@data-provider/react": "2.0.0",
    "prop-types": "15.8.1",
    "react": "18.3.1",
    "react-dom": "18.3.1",
    "react-redux": "8.1.3",
    "redux": "4.2.1"
  },
  "scripts": {
    "start": "DISABLE_ESLINT_PLUGIN=true react-scripts start",
    "build": "DISABLE_ESLINT_PLUGIN=true react-scripts build",
    "serve": "serve -l 3000 --no-request-logging",
    "build:serve": "pnpm run build && pnpm run serve"
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "devDependencies": {
    "react-scripts": "5.0.1",
    "serve": "14.2.6"
  }
}


================================================
FILE: test-e2e/app/public/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="user preferences mock app"
    />
    <title>React App</title>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
  </body>
</html>


================================================
FILE: test-e2e/app/serve.json
================================================
{
  "public": "build",
  "trailingSlash": false,
  "directoryListing": false,
  "cleanUrls": true,
  "rewrites": [
    {
      "source": "/",
      "destination": "/index.html"
    }
  ]
}


================================================
FILE: test-e2e/app/src/App.css
================================================
.App {
  text-align: center;
}

.App-header {
  background-color: #282c34;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-size: calc(10px + 2vmin);
  color: white;
}


================================================
FILE: test-e2e/app/src/App.js
================================================
import { Provider } from "react-redux";
import { createStore, combineReducers } from "redux";
import { storeManager } from "@data-provider/core";
import "./App.css";
import AcceptCookies from "./modules/accept-cookies";
import RejectCookies from "./modules/reject-cookies";
import CookiesValue from "./modules/cookies-value";
import LocalStorageWarning from "./modules/localstorage-warning";

const store = createStore(
  combineReducers({
    dataProviders: storeManager.reducer,
  }),
  globalThis?.__REDUX_DEVTOOLS_EXTENSION__?.(),
);

storeManager.setStore(store, "dataProviders");

function App() {
  return (
    <Provider store={store}>
      <div className="App">
        <header className="App-header">
          <p>
            Click cookies button and reload the page to see how value is
            maintained
          </p>
          <AcceptCookies />
          <RejectCookies />
          <CookiesValue />
          <LocalStorageWarning />
        </header>
      </div>
    </Provider>
  );
}

export default App;


================================================
FILE: test-e2e/app/src/components/cookies-button/CookiesButton.css
================================================
button.cookies-button {
  color: #09d3ac;
  padding: 10px;
  font-size: 20px;
  border: 1px solid #09d3ac;
  background-color: #282828;
  cursor:pointer;
}

button.cookies-button:hover {
  color: #09d3a0;
  background-color: #222;
}

button.cookies-button:disabled, button.cookies-button:disabled:hover  {
  opacity: 0.3;
  color: #09d3ac;
  background-color: #282828;
  cursor:default;
}


================================================
FILE: test-e2e/app/src/components/cookies-button/CookiesButton.js
================================================
import PropTypes from "prop-types";

import "./CookiesButton.css";

export const CookiesButton = ({ visible, onClick, id, text, disabled }) => {
  if (!visible) {
    return null;
  }
  return (
    <button
      onClick={onClick}
      id={id}
      className="cookies-button"
      disabled={disabled}
    >
      {text}
    </button>
  );
};

CookiesButton.propTypes = {
  visible: PropTypes.bool,
  onClick: PropTypes.func,
  id: PropTypes.string,
  text: PropTypes.string,
  disabled: PropTypes.bool,
};


================================================
FILE: test-e2e/app/src/components/cookies-button/index.js
================================================
export { CookiesButton as default } from "./CookiesButton";


================================================
FILE: test-e2e/app/src/components/cookies-value/CookiesValue.js
================================================
import PropTypes from "prop-types";

export const CookiesValue = ({ value }) => {
  return (
    <p>
      Cookies are currently{" "}
      <span id="cookies-value">{value ? "accepted" : "rejected"}</span>
    </p>
  );
};

CookiesValue.propTypes = {
  value: PropTypes.bool,
};


================================================
FILE: test-e2e/app/src/components/cookies-value/index.js
================================================
export { CookiesValue as default } from "./CookiesValue";


================================================
FILE: test-e2e/app/src/data/user-preferences/actions.js
================================================
import { userPreferences } from "./origins";

function log(...args) {
  // eslint-disable-next-line no-console
  console.log(...args);
}

export const acceptCookies = () => {
  // save value directly in another localStorage key for an easier assertions example
  try {
    localStorage.setItem("cookies-accepted", true);
  } catch (err) {
    log("Error setting cookies-accepted", err);
  }

  return userPreferences.queries
    .cookiesAccepted()
    .update(true)
    .catch((err) => {
      log("Error setting user-preferences", err);
    });
};

export const rejectCookies = () => {
  // save value directly in another localStorage key for an easier assertions example
  try {
    localStorage.setItem("cookies-accepted", false);
  } catch (err) {
    log("Error setting cookies-accepted", err);
  }
  return userPreferences.queries
    .cookiesAccepted()
    .update(false)
    .catch((err) => {
      log("Error setting user-preferences", err);
    });
};


================================================
FILE: test-e2e/app/src/data/user-preferences/index.js
================================================
export * from "./origins";
export * from "./selectors";
export * from "./actions";


================================================
FILE: test-e2e/app/src/data/user-preferences/origins.js
================================================
import { LocalStorage } from "@data-provider/browser-storage";

export const userPreferences = new LocalStorage({
  id: "user-preferences",
  storageFallback: false,
});

userPreferences.addQuery("cookiesAccepted", () => ({
  prop: "cookiesAccepted",
}));


================================================
FILE: test-e2e/app/src/data/user-preferences/selectors.js
================================================
import { Selector } from "@data-provider/core";

import { userPreferences } from "./origins";

export const cookiesAccepted = new Selector(
  userPreferences.queries.cookiesAccepted(),
  {
    id: "cookies-accepted",
  },
);


================================================
FILE: test-e2e/app/src/index.css
================================================
body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
    "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
    sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}


================================================
FILE: test-e2e/app/src/index.js
================================================
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";

ReactDOM.render(<App />, document.getElementById("root"));


================================================
FILE: test-e2e/app/src/modules/accept-cookies/AcceptCookies.js
================================================
import { useData, useError } from "@data-provider/react";

import CookiesButton from "../../components/cookies-button";
import { cookiesAccepted, acceptCookies } from "../../data/user-preferences";

const AcceptCookies = () => {
  const accepted = useData(cookiesAccepted);
  const error = useError(cookiesAccepted);
  return (
    <CookiesButton
      visible={!accepted}
      text="Accept cookies"
      id="accept-cookies"
      onClick={acceptCookies}
      disabled={!!error}
    />
  );
};

export default AcceptCookies;


================================================
FILE: test-e2e/app/src/modules/accept-cookies/index.js
================================================
export { default } from "./AcceptCookies";


================================================
FILE: test-e2e/app/src/modules/cookies-value/CookiesValue.js
================================================
import { withData } from "@data-provider/react";

import CookiesValue from "../../components/cookies-value";
import { cookiesAccepted } from "../../data/user-preferences";

export default withData(cookiesAccepted, "value")(CookiesValue);


================================================
FILE: test-e2e/app/src/modules/cookies-value/index.js
================================================
export { default } from "./CookiesValue";


================================================
FILE: test-e2e/app/src/modules/localstorage-warning/LocalStorageWarning.css
================================================
#localstorage-disabled-warning {
  color: #ff9900;
}


================================================
FILE: test-e2e/app/src/modules/localstorage-warning/LocalStorageWarning.js
================================================
import { useError } from "@data-provider/react";

import { cookiesAccepted } from "../../data/user-preferences";

import "./LocalStorageWarning.css";

const LocalStorageWarning = () => {
  const error = useError(cookiesAccepted);

  if (!error) {
    return null;
  }

  return (
    <p id="localstorage-disabled-warning">
      ⚠️ LocalStorage is disabled. Received error:{" "}
      <span id="localstorage-error">{error.message}</span>
    </p>
  );
};

export default LocalStorageWarning;


================================================
FILE: test-e2e/app/src/modules/localstorage-warning/index.js
================================================
export { default } from "./LocalStorageWarning";


================================================
FILE: test-e2e/app/src/modules/reject-cookies/RejectCookies.js
================================================
import { useData } from "@data-provider/react";

import CookiesButton from "../../components/cookies-button";
import { cookiesAccepted, rejectCookies } from "../../data/user-preferences";

const RejectCookies = () => {
  const visible = useData(cookiesAccepted);
  return (
    <CookiesButton
      text="Reject cookies"
      id="reject-cookies"
      onClick={rejectCookies}
      visible={visible}
    />
  );
};

export default RejectCookies;


================================================
FILE: test-e2e/app/src/modules/reject-cookies/index.js
================================================
export { default } from "./RejectCookies";


================================================
FILE: test-e2e/cypress-14/.gitignore
================================================
# See https://help.github.com/ignore-files/ for more about ignoring files.

#environment variables
#.env

# dependencies
/node_modules

# tests
/cypress/screenshots
/cypress/fixtures
/cypress/videos

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*

# ides
.idea
.vs

# caches
.eslintcache


================================================
FILE: test-e2e/cypress-14/babel.config.js
================================================
module.exports = {
  plugins: [
    [
      "module-resolver",
      {
        root: ["."],
        alias: {
          "cypress-localstorage-commands": `../../`,
        },
      },
    ],
  ],
};


================================================
FILE: test-e2e/cypress-14/cypress/plugins/index.js
================================================
/// <reference types="cypress" />
// ***********************************************************
// This example plugins/index.js can be used to load plugins
//
// You can change the location of this file or turn off loading
// the plugins file with the 'pluginsFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/plugins-guide
// ***********************************************************

// This function is called when a project is opened or re-opened (e.g. due to
// the project's config changing)

/**
 * @type {Cypress.PluginConfig}
 */
// eslint-disable-next-line no-unused-vars
const createConfig = (_on, _config) => {
  // `on` is used to hook into various events Cypress emits
  // `config` is the resolved Cypress config
};

module.exports = createConfig;


================================================
FILE: test-e2e/cypress-14/cypress/support/commands.js
================================================
// eslint-disable-next-line import/no-unresolved
import "cypress-localstorage-commands";


================================================
FILE: test-e2e/cypress-14/cypress/support/e2e.js
================================================
import "./commands";


================================================
FILE: test-e2e/cypress-14/cypress.config.js
================================================
const webpackPreprocessor = require("@cypress/webpack-preprocessor");
const defaults = webpackPreprocessor.defaultOptions;

module.exports = {
  e2e: {
    baseUrl: "http://localhost:3000",
    setupNodeEvents(on, config) {
      require("../../src/plugin")(on, config);
      delete defaults.webpackOptions.module.rules[0].use[0].options.presets;
      on("file:preprocessor", webpackPreprocessor(defaults));
      return config;
    },
    specPattern: [
      "../specs/cypress/e2e/*.cy.js",
      "../specs/cypress/e2e/across-specs/save.cy.js",
      "../specs/cypress/e2e/across-specs/restore.cy.js",
      "../specs/cypress/e2e/named-across-specs/save.cy.js",
      "../specs/cypress/e2e/named-across-specs/restore.cy.js",
      "../specs/cypress/e2e/named-across-specs/restore-after-clear.cy.js",
    ],
  },
  video: false,
};


================================================
FILE: test-e2e/cypress-14/package.json
================================================
{
  "name": "cypress-14",
  "private": true,
  "scripts": {
    "build:serve": "cd ../app && pnpm run build:serve",
    "cypress:install": "cypress install",
    "cypress:verify": "cypress verify",
    "cypress:open": "cypress open",
    "cypress:run": "cypress run",
    "test:ci": "start-server-and-test build:serve http-get://localhost:3000 cypress:run"
  },
  "devDependencies": {
    "cypress": "14.5.3"
  }
}


================================================
FILE: test-e2e/cypress-14-no-plugin/.gitignore
================================================
# See https://help.github.com/ignore-files/ for more about ignoring files.

#environment variables
#.env

# dependencies
/node_modules

# tests
/cypress/screenshots
/cypress/fixtures
/cypress/videos

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*

# ides
.idea
.vs

# caches
.eslintcache


================================================
FILE: test-e2e/cypress-14-no-plugin/babel.config.js
================================================
module.exports = {
  plugins: [
    [
      "module-resolver",
      {
        root: ["."],
        alias: {
          "cypress-localstorage-commands": `../../`,
        },
      },
    ],
  ],
};


================================================
FILE: test-e2e/cypress-14-no-plugin/cypress/plugins/index.js
================================================
/// <reference types="cypress" />
// ***********************************************************
// This example plugins/index.js can be used to load plugins
//
// You can change the location of this file or turn off loading
// the plugins file with the 'pluginsFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/plugins-guide
// ***********************************************************

// This function is called when a project is opened or re-opened (e.g. due to
// the project's config changing)

/**
 * @type {Cypress.PluginConfig}
 */
// eslint-disable-next-line no-unused-vars
const createConfig = (_on, _config) => {
  // `on` is used to hook into various events Cypress emits
  // `config` is the resolved Cypress config
};

module.exports = createConfig;


================================================
FILE: test-e2e/cypress-14-no-plugin/cypress/support/commands.js
================================================
// eslint-disable-next-line import/no-unresolved
import "cypress-localstorage-commands";


================================================
FILE: test-e2e/cypress-14-no-plugin/cypress/support/e2e.js
================================================
import "./commands";


================================================
FILE: test-e2e/cypress-14-no-plugin/cypress.config.js
================================================
const webpackPreprocessor = require("@cypress/webpack-preprocessor");
const defaults = webpackPreprocessor.defaultOptions;

module.exports = {
  e2e: {
    baseUrl: "http://localhost:3000",
    setupNodeEvents(on) {
      delete defaults.webpackOptions.module.rules[0].use[0].options.presets;
      on("file:preprocessor", webpackPreprocessor(defaults));
    },
    specPattern: [
      "../specs/cypress/e2e/*.cy.js",
      "../specs/cypress/e2e/no-across-specs/save.cy.js",
      "../specs/cypress/e2e/no-across-specs/restore.cy.js",
    ],
  },
  video: false,
};


================================================
FILE: test-e2e/cypress-14-no-plugin/package.json
================================================
{
  "name": "cypress-14-no-plugin",
  "private": true,
  "scripts": {
    "build:serve": "cd ../app && pnpm run build:serve",
    "cypress:install": "cypress install",
    "cypress:verify": "cypress verify",
    "cypress:open": "cypress open",
    "cypress:run": "cypress run",
    "test:ci": "start-server-and-test build:serve http-get://localhost:3000 cypress:run"
  },
  "devDependencies": {
    "cypress": "14.5.3"
  }
}


================================================
FILE: test-e2e/cypress-9/.gitignore
================================================
# See https://help.github.com/ignore-files/ for more about ignoring files.

#environment variables
#.env

# dependencies
/node_modules

# tests
/cypress/screenshots
/cypress/fixtures
/cypress/videos
/cypress/integration

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*

# ides
.idea
.vs

# caches
.eslintcache


================================================
FILE: test-e2e/cypress-9/babel.config.js
================================================
module.exports = {
  plugins: [
    [
      "module-resolver",
      {
        root: ["."],
        alias: {
          "cypress-localstorage-commands": `../../`,
        },
      },
    ],
  ],
};


================================================
FILE: test-e2e/cypress-9/cypress/.eslintrc.json
================================================
{
  "env": {
    "node": true,
    "es6": true
  },
  "globals": {
    "cy": true,
    "afterEach": true,
    "after": true,
    "before": true,
    "beforeEach": true,
    "describe": true,
    "expect": true,
    "it": true
  }
}


================================================
FILE: test-e2e/cypress-9/cypress/plugins/index.js
================================================
const webpackPreprocessor = require("@cypress/webpack-preprocessor");
const defaults = webpackPreprocessor.defaultOptions;

const plugin = require("../../../../plugin");

const registerPlugins = (on, config) => {
  plugin(on, config);
  delete defaults.webpackOptions.module.rules[0].use[0].options.presets;
  on("file:preprocessor", webpackPreprocessor(defaults));
  return config;
};

module.exports = registerPlugins;


================================================
FILE: test-e2e/cypress-9/cypress/support/commands.js
================================================
// eslint-disable-next-line import/no-unresolved
import "cypress-localstorage-commands";


================================================
FILE: test-e2e/cypress-9/cypress/support/index.js
================================================
import "./commands";


================================================
FILE: test-e2e/cypress-9/cypress.config.js
================================================
module.exports = {
  baseUrl: "http://localhost:3000",
  video: false,
  testFiles: [
    "*.cy.js",
    "across-specs/save.cy.js",
    "across-specs/restore.cy.js",
    "named-across-specs/save.cy.js",
    "named-across-specs/restore.cy.js",
    "named-across-specs/restore-after-clear.cy.js",
  ],
};


================================================
FILE: test-e2e/cypress-9/package.json
================================================
{
  "name": "cypress-9",
  "private": true,
  "scripts": {
    "build:serve": "cd ../app && pnpm run build:serve",
    "cypress:install": "cypress install",
    "cypress:verify": "cypress verify",
    "cypress:open": "cypress open",
    "cypress:run": "cypress run",
    "copy:specs": "node scripts/copySpecs.js",
    "build-and-serve-and-cypress": "start-server-and-test build:serve http-get://localhost:3000 cypress:run",
    "test:ci": "pnpm run copy:specs && pnpm run build-and-serve-and-cypress"
  },
  "devDependencies": {
    "cypress": "9.7.0"
  }
}


================================================
FILE: test-e2e/cypress-9/scripts/copySpecs.js
================================================
const path = require("node:path");
const fsExtra = require("fs-extra");

const rootPath = path.resolve(__dirname, "..");
const destPath = path.resolve(rootPath, "cypress", "integration");
const specsPath = path.resolve(rootPath, "..", "specs", "cypress", "e2e");

const copyLib = () => {
  fsExtra.removeSync(destPath);
  fsExtra.copySync(specsPath, destPath);
};

copyLib();


================================================
FILE: test-e2e/cypress-9-no-plugin/.gitignore
================================================
# See https://help.github.com/ignore-files/ for more about ignoring files.

#environment variables
#.env

# dependencies
/node_modules

# tests
/cypress/screenshots
/cypress/fixtures
/cypress/videos
/cypress/integration

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*

# ides
.idea
.vs

# caches
.eslintcache


================================================
FILE: test-e2e/cypress-9-no-plugin/babel.config.js
================================================
module.exports = {
  plugins: [
    [
      "module-resolver",
      {
        root: ["."],
        alias: {
          "cypress-localstorage-commands": `../../`,
        },
      },
    ],
  ],
};


================================================
FILE: test-e2e/cypress-9-no-plugin/cypress/.eslintrc.json
================================================
{
  "env": {
    "node": true,
    "es6": true
  },
  "globals": {
    "cy": true,
    "afterEach": true,
    "after": true,
    "before": true,
    "beforeEach": true,
    "describe": true,
    "expect": true,
    "it": true
  }
}


================================================
FILE: test-e2e/cypress-9-no-plugin/cypress/plugins/index.js
================================================
const webpackPreprocessor = require("@cypress/webpack-preprocessor");
const defaults = webpackPreprocessor.defaultOptions;

const registerPlugins = (on, config) => {
  delete defaults.webpackOptions.module.rules[0].use[0].options.presets;
  on("file:preprocessor", webpackPreprocessor(defaults));
  return config;
};

module.exports = registerPlugins;


================================================
FILE: test-e2e/cypress-9-no-plugin/cypress/support/commands.js
================================================
// eslint-disable-next-line import/no-unresolved
import "cypress-localstorage-commands";


================================================
FILE: test-e2e/cypress-9-no-plugin/cypress/support/index.js
================================================
import "./commands";


================================================
FILE: test-e2e/cypress-9-no-plugin/cypress.config.js
================================================
module.exports = {
  baseUrl: "http://localhost:3000",
  video: false,
  testFiles: [
    "*.cy.js",
    "no-across-specs/save.cy.js",
    "no-across-specs/restore.cy.js",
  ],
};


================================================
FILE: test-e2e/cypress-9-no-plugin/package.json
================================================
{
  "name": "cypress-9-no-plugin",
  "private": true,
  "scripts": {
    "build:serve": "cd ../app && pnpm run build:serve",
    "cypress:install": "cypress install",
    "cypress:verify": "cypress verify",
    "cypress:open": "cypress open",
    "cypress:run": "cypress run",
    "copy:specs": "node scripts/copySpecs.js",
    "build-and-serve-and-cypress": "start-server-and-test build:serve http-get://localhost:3000 cypress:run",
    "test:ci": "pnpm run copy:specs && pnpm run build-and-serve-and-cypress"
  },
  "devDependencies": {
    "cypress": "9.7.0"
  }
}


================================================
FILE: test-e2e/cypress-9-no-plugin/scripts/copySpecs.js
================================================
const path = require("node:path");
const fsExtra = require("fs-extra");

const rootPath = path.resolve(__dirname, "..");
const destPath = path.resolve(rootPath, "cypress", "integration");
const specsPath = path.resolve(rootPath, "..", "specs", "cypress", "e2e");

const copyLib = () => {
  fsExtra.removeSync(destPath);
  fsExtra.copySync(specsPath, destPath);
};

copyLib();


================================================
FILE: test-e2e/cypress-latest/.gitignore
================================================
# See https://help.github.com/ignore-files/ for more about ignoring files.

#environment variables
#.env

# dependencies
/node_modules

# tests
/cypress/screenshots
/cypress/fixtures
/cypress/videos

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*

# ides
.idea
.vs

# caches
.eslintcache


================================================
FILE: test-e2e/cypress-latest/babel.config.js
================================================
module.exports = {
  plugins: [
    [
      "module-resolver",
      {
        root: ["."],
        alias: {
          "cypress-localstorage-commands": `../../`,
        },
      },
    ],
  ],
};


================================================
FILE: test-e2e/cypress-latest/cypress/plugins/index.js
================================================
/// <reference types="cypress" />
// ***********************************************************
// This example plugins/index.js can be used to load plugins
//
// You can change the location of this file or turn off loading
// the plugins file with the 'pluginsFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/plugins-guide
// ***********************************************************

// This function is called when a project is opened or re-opened (e.g. due to
// the project's config changing)

/**
 * @type {Cypress.PluginConfig}
 */
// eslint-disable-next-line no-unused-vars
const createConfig = (_on, _config) => {
  // `on` is used to hook into various events Cypress emits
  // `config` is the resolved Cypress config
};

module.exports = createConfig;


================================================
FILE: test-e2e/cypress-latest/cypress/support/commands.js
================================================
// eslint-disable-next-line import/no-unresolved
import "cypress-localstorage-commands";


================================================
FILE: test-e2e/cypress-latest/cypress/support/e2e.js
================================================
import "./commands";


================================================
FILE: test-e2e/cypress-latest/cypress.config.js
================================================
const webpackPreprocessor = require("@cypress/webpack-preprocessor");
const defaults = webpackPreprocessor.defaultOptions;

module.exports = {
  e2e: {
    baseUrl: "http://localhost:3000",
    setupNodeEvents(on, config) {
      require("../../src/plugin")(on, config);
      delete defaults.webpackOptions.module.rules[0].use[0].options.presets;
      on("file:preprocessor", webpackPreprocessor(defaults));
      return config;
    },
    specPattern: [
      "../specs/cypress/e2e/*.cy.js",
      "../specs/cypress/e2e/across-specs/save.cy.js",
      "../specs/cypress/e2e/across-specs/restore.cy.js",
      "../specs/cypress/e2e/named-across-specs/save.cy.js",
      "../specs/cypress/e2e/named-across-specs/restore.cy.js",
      "../specs/cypress/e2e/named-across-specs/restore-after-clear.cy.js",
    ],
  },
  video: false,
  allowCypressEnv: false,
};


================================================
FILE: test-e2e/cypress-latest/package.json
================================================
{
  "name": "cypress-latest",
  "private": true,
  "scripts": {
    "build:serve": "cd ../app && pnpm run build:serve",
    "cypress:install": "cypress install",
    "cypress:verify": "cypress verify",
    "cypress:open": "cypress open",
    "cypress:run": "cypress run",
    "test:ci": "start-server-and-test build:serve http-get://localhost:3000 cypress:run"
  },
  "devDependencies": {
    "cypress": "15.10.0"
  }
}


================================================
FILE: test-e2e/cypress-latest-no-plugin/.gitignore
================================================
# See https://help.github.com/ignore-files/ for more about ignoring files.

#environment variables
#.env

# dependencies
/node_modules

# tests
/cypress/screenshots
/cypress/fixtures
/cypress/videos

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*

# ides
.idea
.vs

# caches
.eslintcache


================================================
FILE: test-e2e/cypress-latest-no-plugin/babel.config.js
================================================
module.exports = {
  plugins: [
    [
      "module-resolver",
      {
        root: ["."],
        alias: {
          "cypress-localstorage-commands": `../../`,
        },
      },
    ],
  ],
};


================================================
FILE: test-e2e/cypress-latest-no-plugin/cypress/plugins/index.js
================================================
/// <reference types="cypress" />
// ***********************************************************
// This example plugins/index.js can be used to load plugins
//
// You can change the location of this file or turn off loading
// the plugins file with the 'pluginsFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/plugins-guide
// ***********************************************************

// This function is called when a project is opened or re-opened (e.g. due to
// the project's config changing)

/**
 * @type {Cypress.PluginConfig}
 */
// eslint-disable-next-line no-unused-vars
const createConfig = (_on, _config) => {
  // `on` is used to hook into various events Cypress emits
  // `config` is the resolved Cypress config
};

module.exports = createConfig;


================================================
FILE: test-e2e/cypress-latest-no-plugin/cypress/support/commands.js
================================================
// eslint-disable-next-line import/no-unresolved
import "cypress-localstorage-commands";


================================================
FILE: test-e2e/cypress-latest-no-plugin/cypress/support/e2e.js
================================================
import "./commands";


================================================
FILE: test-e2e/cypress-latest-no-plugin/cypress.config.js
================================================
const webpackPreprocessor = require("@cypress/webpack-preprocessor");
const defaults = webpackPreprocessor.defaultOptions;

module.exports = {
  e2e: {
    baseUrl: "http://localhost:3000",
    setupNodeEvents(on) {
      delete defaults.webpackOptions.module.rules[0].use[0].options.presets;
      on("file:preprocessor", webpackPreprocessor(defaults));
    },
    specPattern: [
      "../specs/cypress/e2e/*.cy.js",
      "../specs/cypress/e2e/no-across-specs/save.cy.js",
      "../specs/cypress/e2e/no-across-specs/restore.cy.js",
    ],
  },
  video: false,
  allowCypressEnv: false,
};


================================================
FILE: test-e2e/cypress-latest-no-plugin/package.json
================================================
{
  "name": "cypress-latest-no-plugin",
  "private": true,
  "scripts": {
    "build:serve": "cd ../app && pnpm run build:serve",
    "cypress:install": "cypress install",
    "cypress:verify": "cypress verify",
    "cypress:open": "cypress open",
    "cypress:run": "cypress run",
    "test:ci": "start-server-and-test build:serve http-get://localhost:3000 cypress:run"
  },
  "devDependencies": {
    "cypress": "15.10.0"
  }
}


================================================
FILE: test-e2e/cypress-typescript/.eslintignore
================================================
/node_modules

================================================
FILE: test-e2e/cypress-typescript/.gitignore
================================================
# See https://help.github.com/ignore-files/ for more about ignoring files.

#environment variables
#.env

# dependencies
/node_modules

#build
/build

# tests
/cypress/screenshots
/cypress/fixtures

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*

# ides
.idea
.vs

# Generated files
/cypress/support/cypress-localstorage-commands

# caches
.eslintcache


================================================
FILE: test-e2e/cypress-typescript/cypress/e2e/assertions-example.cy.ts
================================================
// Next reference is commented as package is not available at node_modules
//// <reference types="cypress-localstorage-commands" />

describe("localStorage cookies-accepted item", () => {
  beforeEach(() => {
    cy.restoreLocalStorage();
    cy.visit("/");
  });

  afterEach(() => {
    cy.saveLocalStorage();
  });

  it("should be null first time page is visited", () => {
    cy.getLocalStorage("cookies-accepted").should("equal", null);
  });

  it("should be true after clicking cookies button", () => {
    cy.get("#accept-cookies").click();
    cy.getLocalStorage("cookies-accepted").should("equal", "true");
  });

  it("should be true after reloading", () => {
    cy.getLocalStorage("cookies-accepted").then((cookiesAccepted) => {
      if (cookiesAccepted !== null) {
        expect(JSON.parse(cookiesAccepted)).to.equal(true);
      }
      expect(cookiesAccepted).to.equal("true");
    });
  });
});


================================================
FILE: test-e2e/cypress-typescript/cypress/e2e/cookies-example.cy.ts
================================================
// Next reference is commented as package is not available at node_modules
//// <reference types="cypress-localstorage-commands" />

describe("Accept cookies button", () => {
  const COOKIES_BUTTON = "#accept-cookies";
  const LOCALSTORAGE_DISABLED_WARNING = "#localstorage-disabled-warning";
  const LOCALSTORAGE_ERROR = "#localstorage-error";

  before(() => {
    cy.clearLocalStorageSnapshot();
  });

  beforeEach(() => {
    cy.restoreLocalStorage();
    cy.visit("/");
  });

  afterEach(() => {
    cy.saveLocalStorage();
  });

  it("should be visible", () => {
    cy.get(COOKIES_BUTTON).should("be.visible");
  });

  it("should not be visible after clicked", () => {
    cy.get(COOKIES_BUTTON).click();
    cy.get(COOKIES_BUTTON).should("not.exist");
  });

  it("should still be visible when reloading if localStorage is disabled", () => {
    cy.disableLocalStorage();
    cy.reload();
    cy.get(COOKIES_BUTTON).should("be.visible");
  });

  it("should display warning if localStorage is disabled", () => {
    cy.disableLocalStorage();
    cy.reload();
    cy.get(LOCALSTORAGE_DISABLED_WARNING).should("be.visible");
  });

  it("should display localStorage error message", () => {
    cy.disableLocalStorage();
    cy.reload();
    cy.get(LOCALSTORAGE_ERROR).should("have.text", "Error");
  });

  it("should not be visible after reloading", () => {
    cy.get(COOKIES_BUTTON).should("not.exist");
  });
});


================================================
FILE: test-e2e/cypress-typescript/cypress/e2e/cookies.cy.ts
================================================
// Next reference is commented as package is not available at node_modules
//// <reference types="cypress-localstorage-commands" />

describe("Cookies", () => {
  const SELECTORS = {
    ACCEPT_BUTTON: "#accept-cookies",
    REJECT_BUTTON: "#reject-cookies",
    LOCALSTORAGE_DISABLED_WARNING: "#localstorage-disabled-warning",
  };

  beforeEach(() => {
    cy.visit("/");
  });

  describe("when cookies are not accepted", () => {
    it("should display accept cookies button", () => {
      cy.get(SELECTORS.ACCEPT_BUTTON).should("be.visible");
    });
  });

  describe("when user click accept cookies button", () => {
    describe("without using localStorage commands", () => {
      it("should display reject cookies button", () => {
        cy.get(SELECTORS.ACCEPT_BUTTON).click();
        cy.get(SELECTORS.REJECT_BUTTON).should("be.visible");
      });

      it("should accept cookies button after reloading page", () => {
        cy.reload();
        cy.getLocalStorage("cookies-accepted").should("not.exist");
        cy.get(SELECTORS.ACCEPT_BUTTON).should("be.visible");
      });
    });

    describe("saving and restoring local storage", () => {
      it("should display reject cookies button", () => {
        cy.getLocalStorage("cookies-accepted").should("not.exist");
        cy.get(SELECTORS.ACCEPT_BUTTON).click();
        cy.getLocalStorage("cookies-accepted").should("equal", "true");
        cy.get(SELECTORS.REJECT_BUTTON).should("be.visible");
        cy.saveLocalStorage();
      });

      it("should display reject cookies button after reloading page", () => {
        cy.restoreLocalStorage();
        cy.reload();
        cy.getLocalStorage("cookies-accepted").should("equal", "true");
        cy.get(SELECTORS.REJECT_BUTTON).should("be.visible");
      });
    });
  });

  describe("restoring localStorage, when user click rejects cookies button", () => {
    it("should display accept cookies button", () => {
      cy.restoreLocalStorage();
      cy.reload();
      cy.getLocalStorage("cookies-accepted").should("equal", "true");
      cy.get(SELECTORS.REJECT_BUTTON).click();
      cy.getLocalStorage("cookies-accepted").should("equal", "false");
      cy.get(SELECTORS.ACCEPT_BUTTON).should("be.visible");
      cy.saveLocalStorage();
    });

    it("should display accept-cookies cookies button after reloading page", () => {
      cy.restoreLocalStorage();
      cy.reload();
      cy.getLocalStorage("cookies-accepted").should("equal", "false");
      cy.get(SELECTORS.ACCEPT_BUTTON).should("be.visible");
    });

    it("should display reject-cookies cookies button after clicking accept-cookies button again", () => {
      cy.restoreLocalStorage();
      cy.reload();
      cy.getLocalStorage("cookies-accepted").should("equal", "false");
      cy.get(SELECTORS.ACCEPT_BUTTON).click();
      cy.getLocalStorage("cookies-accepted").should("equal", "true");
      cy.get(SELECTORS.REJECT_BUTTON).should("be.visible");
      cy.saveLocalStorage();
    });
  });

  describe("after clearing localStorage snapshot", () => {
    before(() => {
      cy.clearLocalStorageSnapshot();
    });

    it("should display accept cookies button", () => {
      cy.restoreLocalStorage();
      cy.reload();
      cy.getLocalStorage("cookies-accepted").should("not.exist");
      cy.get(SELECTORS.ACCEPT_BUTTON).should("be.visible");
      cy.saveLocalStorage();
    });

    it("should display reject cookies button after clicking button", () => {
      cy.restoreLocalStorage();
      cy.reload();
      cy.getLocalStorage("cookies-accepted").should("not.exist");
      cy.get(SELECTORS.ACCEPT_BUTTON).click();
      cy.getLocalStorage("cookies-accepted").should("equal", "true");
      cy.get(SELECTORS.REJECT_BUTTON).should("be.visible");
      cy.saveLocalStorage();
    });
  });

  describe("disabling localStorage", () => {
    it("should not get previous localStorage value", () => {
      cy.disableLocalStorage();
      cy.reload();
      cy.restoreLocalStorage();
      cy.reload();
      cy.getLocalStorage("cookies-accepted").should("not.exist");
    });

    it("should display warning if localStorage is disabled", () => {
      cy.disableLocalStorage();
      cy.reload();
      cy.get(SELECTORS.LOCALSTORAGE_DISABLED_WARNING).should("be.visible");
    });

    it("should not set cookiesAccepted localStorage value when user clicks accept cookies button", () => {
      cy.disableLocalStorage();
      cy.reload();
      cy.getLocalStorage("cookies-accepted").should("not.exist");
      cy.get(SELECTORS.ACCEPT_BUTTON).click({ force: true });
      cy.getLocalStorage("cookies-accepted").should("not.exist");
      // eslint-disable-next-line cypress/no-unnecessary-waiting
      cy.wait(500);
      cy.get(SELECTORS.REJECT_BUTTON).should("not.exist");
    });

    it("should not throw when calling to setLocalStorage, getLocalStorage or removeLocalStorage commands", () => {
      cy.disableLocalStorage();
      cy.reload();
      cy.setLocalStorage("user-preferences", '{"cookiesAccepted":false}');
      cy.getLocalStorage("user-preferences").should("not.exist");
      cy.removeLocalStorage("user-preferences");
      cy.getLocalStorage("user-preferences").should("not.exist");
    });

    it("should not throw when calling to restoreLocalStorage", () => {
      cy.disableLocalStorage();
      cy.reload();
      cy.restoreLocalStorage();
      cy.getLocalStorage("user-preferences").should("not.exist");
    });

    it("should keep storage disabled in the same test", () => {
      cy.setLocalStorage("user-preferences", '{"cookiesAccepted":true}');
      cy.saveLocalStorage();
      cy.disableLocalStorage();
      cy.reload();
      cy.restoreLocalStorage();
      cy.reload();
      cy.getLocalStorage("user-preferences").should("not.exist");
    });

    it("should not clear previous localStorage snapshot", () => {
      cy.restoreLocalStorage();
      cy.reload();
      cy.getLocalStorage("user-preferences").should(
        "equal",
        '{"cookiesAccepted":true}',
      );
    });

    it("should not throw when reloading multiple times", () => {
      cy.disableLocalStorage();
      cy.reload();
      cy.getLocalStorage("user-preferences").should("not.exist");
      cy.disableLocalStorage();
      cy.reload();
      cy.getLocalStorage("user-preferences").should("not.exist");
      cy.restoreLocalStorage();
      cy.reload();
      cy.getLocalStorage("user-preferences");
      cy.disableLocalStorage();
      cy.reload();
      cy.getLocalStorage("user-preferences").should("not.exist");
    });
  });

  describe("when using setLocalStorage command to manually set user-preferences value", () => {
    it("should display reject cookies button", () => {
      cy.setLocalStorage("user-preferences", '{"cookiesAccepted":true}');
      cy.reload();
      cy.get(SELECTORS.REJECT_BUTTON).should("be.visible");
      cy.saveLocalStorage();
    });
  });

  describe("when using getLocalStorage command to manually get localStorage items", () => {
    it("should return current localStorage values", () => {
      cy.restoreLocalStorage();
      cy.reload();
      cy.get(SELECTORS.REJECT_BUTTON).should("be.visible");
      cy.getLocalStorage("user-preferences").should(
        "equal",
        '{"cookiesAccepted":true}',
      );
      cy.setLocalStorage("user-preferences", '{"cookiesAccepted":false}');
      cy.getLocalStorage("user-preferences").should(
        "equal",
        '{"cookiesAccepted":false}',
      );
      cy.saveLocalStorage();
    });
  });

  describe("when using removeLocalStorage command to manually remove localStorage item", () => {
    it("should remove item from localStorage", () => {
      cy.restoreLocalStorage();
      cy.reload();
      cy.getLocalStorage("user-preferences").should(
        "equal",
        '{"cookiesAccepted":false}',
      );
      cy.get(SELECTORS.ACCEPT_BUTTON).should("be.visible");
      cy.removeLocalStorage("user-preferences");
      cy.getLocalStorage("user-preferences").should("equal", null);
    });

    it("should have not removed item from localStorage snapshot", () => {
      cy.restoreLocalStorage();
      cy.reload();
      cy.getLocalStorage("user-preferences").should(
        "equal",
        '{"cookiesAccepted":false}',
      );
      cy.get(SELECTORS.ACCEPT_BUTTON).should("be.visible");
      cy.removeLocalStorage("user-preferences");
      cy.saveLocalStorage();
    });

    it("should have removed item from localStorage snapshot after saving it", () => {
      cy.setLocalStorage("user-preferences", '{"cookiesAccepted":true}');
      cy.reload();
      cy.get(SELECTORS.REJECT_BUTTON).should("be.visible");
      cy.restoreLocalStorage();
      cy.getLocalStorage("user-preferences").should("not.exist");
    });
  });
});


================================================
FILE: test-e2e/cypress-typescript/cypress/e2e/localstorage-disabled.cy.ts
================================================
// Next reference is commented as package is not available at node_modules
//// <reference types="cypress-localstorage-commands" />

describe("when localStorage is disabled", () => {
  beforeEach(() => {
    cy.disableLocalStorage({
      withError: new Error("Disabled by cypress-localstorage-commands"),
    });
    cy.visit("/");
  });

  it("should display localStorage warning", () => {
    cy.get("#localstorage-disabled-warning").should("be.visible");
  });

  it("should display localStorage error message", () => {
    cy.get("#localstorage-error").should(
      "have.text",
      "Disabled by cypress-localstorage-commands",
    );
  });

  it("should display accept-cookies button disabled", () => {
    cy.get("#accept-cookies").should("be.disabled");
  });
});


================================================
FILE: test-e2e/cypress-typescript/cypress/e2e/named-snapshots.cy.ts
================================================
// Next reference is commented as package is not available at node_modules
//// <reference types="cypress-localstorage-commands" />

describe("Accept cookies button using named snapshots", () => {
  const COOKIES_BUTTON = "#accept-cookies";

  before(() => {
    cy.clearLocalStorageSnapshot();
  });

  beforeEach(() => {
    cy.visit("/");
  });

  it("should be visible", () => {
    cy.get(COOKIES_BUTTON).should("be.visible");
    cy.saveLocalStorage("cookies-not-accepted");
  });

  it("should not be visible after clicked", () => {
    cy.get(COOKIES_BUTTON).click();
    cy.get(COOKIES_BUTTON).should("not.exist");
    cy.saveLocalStorage("cookies-accepted");
  });

  it("should be visible when cookies are not accepted", () => {
    cy.restoreLocalStorage("cookies-not-accepted");
    cy.reload();
    cy.get(COOKIES_BUTTON).should("be.visible");
  });

  it("should not be visible when cookies are accepted", () => {
    cy.restoreLocalStorage("cookies-accepted");
    cy.reload();
    cy.get(COOKIES_BUTTON).should("not.exist");
  });

  it("should be visible after clearing localStorage snapshot", () => {
    cy.clearLocalStorageSnapshot("cookies-accepted");
    cy.restoreLocalStorage("cookies-accepted");
    cy.reload();
    cy.get(COOKIES_BUTTON).should("be.visible");
  });
});


================================================
FILE: test-e2e/cypress-typescript/cypress/support/commands.js
================================================
// eslint-disable-next-line import/no-unresolved
import "./cypress-localstorage-commands";


================================================
FILE: test-e2e/cypress-typescript/cypress/support/e2e.js
================================================
// Import commands.js using ES2015 syntax:
import "./commands";

// Alternatively you can use CommonJS syntax:
// require('./commands')


================================================
FILE: test-e2e/cypress-typescript/cypress.config.ts
================================================
// eslint-disable-next-line @typescript-eslint/no-require-imports
import plugin = require("./cypress/support/cypress-localstorage-commands/plugin");

export default {
  e2e: {
    baseUrl: "http://localhost:3000",
    setupNodeEvents(on, config) {
      plugin(on, config);
    },
  },
  video: false,
  allowCypressEnv: false,
};


================================================
FILE: test-e2e/cypress-typescript/package.json
================================================
{
  "name": "cypress-typescript",
  "version": "1.0.0",
  "private": true,
  "scripts": {
    "prelint": "pnpm run copy:library",
    "lint": "eslint scripts cypress",
    "build:serve": "cd ../app && pnpm run build:serve",
    "cypress:install": "cypress install",
    "cypress:verify": "cypress verify",
    "cypress:open": "cypress open",
    "cypress:run": "cypress run",
    "copy:library": "node scripts/copyLibrary.js",
    "build-and-serve-and-cypress": "start-server-and-test build:serve http-get://localhost:3000 cypress:run",
    "test:ci": "pnpm run copy:library && pnpm run build-and-serve-and-cypress"
  },
  "devDependencies": {
    "cypress": "15.10.0"
  }
}


================================================
FILE: test-e2e/cypress-typescript/scripts/copyLibrary.js
================================================
const path = require("node:path");
const fsExtra = require("fs-extra");

const rootPath = path.resolve(__dirname, "..");
const rootLibPath = path.resolve(rootPath, "..", "..");
const destPath = path.resolve(
  rootPath,
  "cypress",
  "support",
  "cypress-localstorage-commands",
);

const SRC_FOLDER = "src";
const INDEX_FILE = "index.js";
const INDEX_TS_FILE = "index.d.ts";
const PLUGIN_FILE = "plugin.js";
const PLUGIN_TS_FILE = "plugin.d.ts";

const libPath = path.resolve(rootLibPath, SRC_FOLDER);
const indexFile = path.resolve(rootLibPath, INDEX_FILE);
const indexTsFile = path.resolve(rootLibPath, INDEX_TS_FILE);
const pluginFile = path.resolve(rootLibPath, PLUGIN_FILE);
const pluginTsFile = path.resolve(rootLibPath, PLUGIN_TS_FILE);

const copyLib = () => {
  fsExtra.removeSync(destPath);
  fsExtra.ensureDirSync(destPath);
  fsExtra.copySync(libPath, path.resolve(destPath, SRC_FOLDER));
  fsExtra.copySync(indexFile, path.resolve(destPath, INDEX_FILE));
  fsExtra.copySync(indexTsFile, path.resolve(destPath, INDEX_TS_FILE));
  fsExtra.copySync(pluginFile, path.resolve(destPath, PLUGIN_FILE));
  fsExtra.copySync(pluginTsFile, path.resolve(destPath, PLUGIN_TS_FILE));
};

copyLib();


================================================
FILE: test-e2e/cypress-typescript/tsconfig.json
================================================
{
  "compilerOptions": {
    "target": "es6",
    "module": "commonjs",
    "outDir": "dist",
    "moduleResolution": "node",
    "types": ["cypress"]
  },
  "include": [
    "**/*.ts"
  ],
  "exclude": [
    "node_modules"
  ]
}


================================================
FILE: test-e2e/specs/cypress/e2e/across-specs/restore.cy.js
================================================
describe("Cookies buttons", () => {
  const ACCEPT_BUTTON = "#accept-cookies";
  const REJECT_BUTTON = "#reject-cookies";

  beforeEach(() => {
    cy.restoreLocalStorage();
    cy.visit("/");
  });

  it("accept should not be visible after loading", () => {
    cy.get(ACCEPT_BUTTON).should("not.exist");
  });

  it("reject should be visible", () => {
    cy.get(REJECT_BUTTON).should("be.visible");
  });
});


================================================
FILE: test-e2e/specs/cypress/e2e/across-specs/save.cy.js
================================================
describe("Cookies buttons", () => {
  const ACCEPT_BUTTON = "#accept-cookies";
  const REJECT_BUTTON = "#reject-cookies";

  before(() => {
    cy.clearLocalStorageSnapshot();
  });

  beforeEach(() => {
    cy.restoreLocalStorage();
    cy.visit("/");
  });

  afterEach(() => {
    cy.saveLocalStorage();
  });

  it("accept should be visible", () => {
    cy.get(ACCEPT_BUTTON).should("be.visible");
  });

  it("accept should not be visible after clicked", () => {
    cy.get(ACCEPT_BUTTON).click();
    cy.get(ACCEPT_BUTTON).should("not.exist");
  });

  it("reject should not be visible", () => {
    cy.get(REJECT_BUTTON).should("be.visible");
  });

  it("reject should still be visible after reloading", () => {
    cy.get(REJECT_BUTTON).should("be.visible");
    cy.get(ACCEPT_BUTTON).should("not.exist");
  });
});


================================================
FILE: test-e2e/specs/cypress/e2e/assertions-example.cy.js
================================================
describe("localStorage cookies-accepted item", () => {
  beforeEach(() => {
    cy.restoreLocalStorage();
    cy.visit("/");
  });

  afterEach(() => {
    cy.saveLocalStorage();
  });

  it("should be null first time page is visited", () => {
    cy.getLocalStorage("cookies-accepted").should("equal", null);
  });

  it("should be true after clicking cookies button", () => {
    cy.get("#accept-cookies").click();
    cy.getLocalStorage("cookies-accepted").should("equal", "true");
  });

  it("should be true after reloading", () => {
    cy.getLocalStorage("cookies-accepted").then((cookiesAccepted) => {
      expect(cookiesAccepted).to.equal("true");
    });
  });
});


================================================
FILE: test-e2e/specs/cypress/e2e/cookies-example.cy.js
================================================
describe("Accept cookies button", () => {
  const COOKIES_BUTTON = "#accept-cookies";
  const LOCALSTORAGE_DISABLED_WARNING = "#localstorage-disabled-warning";
  const LOCALSTORAGE_ERROR = "#localstorage-error";

  before(() => {
    cy.clearLocalStorageSnapshot();
  });

  beforeEach(() => {
    cy.restoreLocalStorage();
    cy.visit("/");
  });

  afterEach(() => {
    cy.saveLocalStorage();
  });

  it("should be visible", () => {
    cy.get(COOKIES_BUTTON).should("be.visible");
  });

  it("should not be visible after clicked", () => {
    cy.get(COOKIES_BUTTON).click();
    cy.get(COOKIES_BUTTON).should("not.exist");
  });

  it("should still be visible when reloading if localStorage is disabled", () => {
    cy.disableLocalStorage();
    cy.reload();
    cy.get(COOKIES_BUTTON).should("be.visible");
  });

  it("should display warning if localStorage is disabled", () => {
    cy.disableLocalStorage();
    cy.reload();
    cy.get(LOCALSTORAGE_DISABLED_WARNING).should("be.visible");
  });

  it("should display localStorage error message", () => {
    cy.disableLocalStorage();
    cy.reload();
    cy.get(LOCALSTORAGE_ERROR).should("have.text", "Error");
  });

  it("should not be visible after reloading", () => {
    cy.get(COOKIES_BUTTON).should("not.exist");
  });
});


================================================
FILE: test-e2e/specs/cypress/e2e/cookies.cy.js
================================================
describe("Cookies", () => {
  const SELECTORS = {
    ACCEPT_BUTTON: "#accept-cookies",
    REJECT_BUTTON: "#reject-cookies",
    LOCALSTORAGE_DISABLED_WARNING: "#localstorage-disabled-warning",
  };

  beforeEach(() => {
    cy.visit("/");
  });

  describe("when cookies are not accepted", () => {
    before(() => {
      cy.visit("/");
    });

    it("should display accept cookies button", () => {
      cy.get(SELECTORS.ACCEPT_BUTTON).should("be.visible");
    });
  });

  describe("when user click accept cookies button", () => {
    describe("without using localStorage commands", () => {
      it("should display reject cookies button", () => {
        cy.get(SELECTORS.ACCEPT_BUTTON).click();
        cy.get(SELECTORS.REJECT_BUTTON).should("be.visible");
      });

      it("should accept cookies button after reloading page", () => {
        cy.getLocalStorage("cookies-accepted").should("not.exist");
        cy.get(SELECTORS.ACCEPT_BUTTON).should("be.visible");
      });
    });

    describe("saving and restoring local storage", () => {
      it("should display reject cookies button", () => {
        cy.getLocalStorage("cookies-accepted").should("not.exist");
        cy.get(SELECTORS.ACCEPT_BUTTON).click();
        cy.getLocalStorage("cookies-accepted").should("equal", "true");
        cy.get(SELECTORS.REJECT_BUTTON).should("be.visible");
        cy.saveLocalStorage();
      });

      it("should display reject cookies button after reloading page", () => {
        cy.restoreLocalStorage();
        cy.reload();
        cy.getLocalStorage("cookies-accepted").should("equal", "true");
        cy.get(SELECTORS.REJECT_BUTTON).should("be.visible");
      });
    });
  });

  describe("restoring localStorage, when user click rejects cookies button", () => {
    it("should display accept cookies button", () => {
      cy.restoreLocalStorage();
      cy.reload();
      cy.getLocalStorage("cookies-accepted").should("equal", "true");
      cy.get(SELECTORS.REJECT_BUTTON).click();
      cy.getLocalStorage("cookies-accepted").should("equal", "false");
      cy.get(SELECTORS.ACCEPT_BUTTON).should("be.visible");
      cy.saveLocalStorage();
    });

    it("should display accept-cookies cookies button after reloading page", () => {
      cy.restoreLocalStorage();
      cy.reload();
      cy.getLocalStorage("cookies-accepted").should("equal", "false");
      cy.get(SELECTORS.ACCEPT_BUTTON).should("be.visible");
    });

    it("should display reject-cookies cookies button after clicking accept-cookies button again", () => {
      cy.restoreLocalStorage();
      cy.reload();
      cy.getLocalStorage("cookies-accepted").should("equal", "false");
      cy.get(SELECTORS.ACCEPT_BUTTON).click();
      cy.getLocalStorage("cookies-accepted").should("equal", "true");
      cy.get(SELECTORS.REJECT_BUTTON).should("be.visible");
      cy.saveLocalStorage();
    });
  });

  describe("after clearing localStorage snapshot", () => {
    before(() => {
      cy.clearLocalStorageSnapshot();
    });

    it("should display accept cookies button", () => {
      cy.restoreLocalStorage();
      cy.reload();
      cy.getLocalStorage("cookies-accepted").should("not.exist");
      cy.get(SELECTORS.ACCEPT_BUTTON).should("be.visible");
      cy.saveLocalStorage();
    });

    it("should display reject cookies button after clicking button", () => {
      cy.restoreLocalStorage();
      cy.reload();
      cy.getLocalStorage("cookies-accepted").should("not.exist");
      cy.get(SELECTORS.ACCEPT_BUTTON).click();
      cy.getLocalStorage("cookies-accepted").should("equal", "true");
      cy.get(SELECTORS.REJECT_BUTTON).should("be.visible");
      cy.saveLocalStorage();
    });
  });

  describe("disabling localStorage", () => {
    it("should not get previous localStorage value", () => {
      cy.disableLocalStorage();
      cy.reload();
      cy.restoreLocalStorage();
      cy.reload();
      cy.getLocalStorage("cookies-accepted").should("not.exist");
    });

    it("should display warning if localStorage is disabled", () => {
      cy.disableLocalStorage();
      cy.reload();
      cy.get(SELECTORS.LOCALSTORAGE_DISABLED_WARNING).should("be.visible");
    });

    it("should not set cookiesAccepted localStorage value when user clicks accept cookies button", () => {
      cy.disableLocalStorage();
      cy.reload();
      cy.getLocalStorage("cookies-accepted").should("not.exist");
      cy.get(SELECTORS.ACCEPT_BUTTON).click({ force: true });
      cy.getLocalStorage("cookies-accepted").should("not.exist");
      // eslint-disable-next-line cypress/no-unnecessary-waiting
      cy.wait(500);
      cy.get(SELECTORS.REJECT_BUTTON).should("not.exist");
    });

    it("should not throw when calling to setLocalStorage, getLocalStorage or removeLocalStorage commands", () => {
      cy.disableLocalStorage();
      cy.reload();
      cy.setLocalStorage("user-preferences", '{"cookiesAccepted":false}');
      cy.getLocalStorage("user-preferences").should("not.exist");
      cy.removeLocalStorage("user-preferences");
      cy.getLocalStorage("user-preferences").should("not.exist");
    });

    it("should not throw when calling to restoreLocalStorage", () => {
      cy.disableLocalStorage();
      cy.reload();
      cy.restoreLocalStorage();
      cy.getLocalStorage("user-preferences").should("not.exist");
    });

    it("should keep storage disabled in the same test", () => {
      cy.setLocalStorage("user-preferences", '{"cookiesAccepted":true}');
      cy.saveLocalStorage();
      cy.disableLocalStorage();
      cy.reload();
      cy.restoreLocalStorage();
      cy.reload();
      cy.getLocalStorage("user-preferences").should("not.exist");
    });

    it("should not clear previous localStorage snapshot", () => {
      cy.restoreLocalStorage();
      cy.reload();
      cy.getLocalStorage("user-preferences").should(
        "equal",
        '{"cookiesAccepted":true}',
      );
    });

    it("should not throw when reloading multiple times", () => {
      cy.disableLocalStorage();
      cy.reload();
      cy.getLocalStorage("user-preferences").should("not.exist");
      cy.disableLocalStorage();
      cy.reload();
      cy.getLocalStorage("user-preferences").should("not.exist");
      cy.restoreLocalStorage();
      cy.reload();
      cy.getLocalStorage("user-preferences");
      cy.disableLocalStorage();
      cy.reload();
      cy.getLocalStorage("user-preferences").should("not.exist");
    });
  });

  describe("when using setLocalStorage command to manually set user-preferences value", () => {
    it("should display reject cookies button", () => {
      cy.setLocalStorage("user-preferences", '{"cookiesAccepted":true}');
      cy.reload();
      cy.get(SELECTORS.REJECT_BUTTON).should("be.visible");
      cy.saveLocalStorage();
    });
  });

  describe("when using getLocalStorage command to manually get localStorage items", () => {
    it("should return current localStorage values", () => {
      cy.restoreLocalStorage();
      cy.reload();
      cy.get(SELECTORS.REJECT_BUTTON).should("be.visible");
      cy.getLocalStorage("user-preferences").should(
        "equal",
        '{"cookiesAccepted":true}',
      );
      cy.setLocalStorage("user-preferences", '{"cookiesAccepted":false}');
      cy.getLocalStorage("user-preferences").should(
        "equal",
        '{"cookiesAccepted":false}',
      );
      cy.saveLocalStorage();
    });
  });

  describe("when using removeLocalStorage command to manually remove localStorage item", () => {
    it("should remove item from localStorage", () => {
      cy.restoreLocalStorage();
      cy.reload();
      cy.getLocalStorage("user-preferences").should(
        "equal",
        '{"cookiesAccepted":false}',
      );
      cy.get(SELECTORS.ACCEPT_BUTTON).should("be.visible");
      cy.removeLocalStorage("user-preferences");
      cy.getLocalStorage("user-preferences").should("equal", null);
    });

    it("should have not removed item from localStorage snapshot", () => {
      cy.restoreLocalStorage();
      cy.reload();
      cy.getLocalStorage("user-preferences").should(
        "equal",
        '{"cookiesAccepted":false}',
      );
      cy.get(SELECTORS.ACCEPT_BUTTON).should("be.visible");
      cy.removeLocalStorage("user-preferences");
      cy.saveLocalStorage();
    });

    it("should have removed item from localStorage snapshot after saving it", () => {
      cy.setLocalStorage("user-preferences", '{"cookiesAccepted":true}');
      cy.reload();
      cy.get(SELECTORS.REJECT_BUTTON).should("be.visible");
      cy.restoreLocalStorage();
      cy.getLocalStorage("user-preferences").should("not.exist");
    });
  });
});


================================================
FILE: test-e2e/specs/cypress/e2e/localstorage-disabled.cy.js
================================================
describe("when localStorage is disabled", () => {
  beforeEach(() => {
    cy.disableLocalStorage({
      withError: new Error("Disabled by cypress-localstorage-commands"),
    });
    cy.visit("/");
  });

  it("should display localStorage warning", () => {
    cy.get("#localstorage-disabled-warning").should("be.visible");
  });

  it("should display localStorage error message", () => {
    cy.get("#localstorage-error").should(
      "have.text",
      "Disabled by cypress-localstorage-commands",
    );
  });

  it("should display accept-cookies button disabled", () => {
    cy.get("#accept-cookies").should("be.disabled");
  });
});


================================================
FILE: test-e2e/specs/cypress/e2e/named-across-specs/restore-after-clear.cy.js
================================================
describe("Cookies buttons", () => {
  const ACCEPT_BUTTON = "#accept-cookies";

  it("accept should be visible after clearing localStorage snapshot", () => {
    cy.restoreLocalStorage("cookies-accepted");
    cy.visit("/");
    cy.get(ACCEPT_BUTTON).should("be.visible");
  });
});


================================================
FILE: test-e2e/specs/cypress/e2e/named-across-specs/restore.cy.js
================================================
describe("Cookies buttons", () => {
  const ACCEPT_BUTTON = "#accept-cookies";

  it("accept should not be visible after loading", () => {
    cy.restoreLocalStorage("cookies-accepted");
    cy.visit("/");
    cy.get(ACCEPT_BUTTON).should("not.exist");
  });

  it("accept should be visible after clearing localStorage snapshot", () => {
    cy.clearLocalStorageSnapshot("cookies-accepted");
    cy.restoreLocalStorage("cookies-accepted");
    cy.visit("/");
    cy.get(ACCEPT_BUTTON).should("be.visible");
  });
});


================================================
FILE: test-e2e/specs/cypress/e2e/named-across-specs/save.cy.js
================================================
describe("Cookies buttons", () => {
  const ACCEPT_BUTTON = "#accept-cookies";

  before(() => {
    cy.clearLocalStorageSnapshot();
  });

  beforeEach(() => {
    cy.visit("/");
  });

  it("accept should be visible", () => {
    cy.get(ACCEPT_BUTTON).should("be.visible");
    cy.saveLocalStorage("cookies-not-accepted");
  });

  it("accept should not be visible after clicked", () => {
    cy.get(ACCEPT_BUTTON).click();
    cy.get(ACCEPT_BUTTON).should("not.exist");
    cy.saveLocalStorage("cookies-accepted");
  });

  it("accept should be visible when cookies are not accepted", () => {
    cy.restoreLocalStorage("cookies-not-accepted");
    cy.visit("/");
    cy.get(ACCEPT_BUTTON).should("be.visible");
  });

  it("should not be visible when cookies are accepted", () => {
    cy.restoreLocalStorage("cookies-accepted");
    cy.visit("/");
    cy.get(ACCEPT_BUTTON).should("not.exist");
  });
});


================================================
FILE: test-e2e/specs/cypress/e2e/named-snapshots.cy.js
================================================
describe("Accept cookies button using named snapshots", () => {
  const COOKIES_BUTTON = "#accept-cookies";

  before(() => {
    cy.clearLocalStorageSnapshot();
    cy.visit("/");
  });

  beforeEach(() => {
    cy.visit("/");
  });

  it("should be visible", () => {
    cy.get(COOKIES_BUTTON).should("be.visible");
    cy.saveLocalStorage("cookies-not-accepted");
  });

  it("should not be visible after clicked", () => {
    cy.get(COOKIES_BUTTON).click();
    cy.get(COOKIES_BUTTON).should("not.exist");
    cy.saveLocalStorage("cookies-accepted");
  });

  it("should be visible when cookies are not accepted", () => {
    cy.restoreLocalStorage("cookies-not-accepted");
    cy.reload();
    cy.get(COOKIES_BUTTON).should("be.visible");
  });

  it("should not be visible when cookies are accepted", () => {
    cy.restoreLocalStorage("cookies-accepted");
    cy.reload();
    cy.get(COOKIES_BUTTON).should("not.exist");
  });

  it("should be visible after clearing localStorage snapshot", () => {
    cy.clearLocalStorageSnapshot("cookies-accepted");
    cy.restoreLocalStorage("cookies-accepted");
    cy.reload();
    cy.get(COOKIES_BUTTON).should("be.visible");
  });
});


================================================
FILE: test-e2e/specs/cypress/e2e/no-across-specs/restore.cy.js
================================================
describe("Cookies buttons", () => {
  const ACCEPT_BUTTON = "#accept-cookies";
  const REJECT_BUTTON = "#reject-cookies";

  beforeEach(() => {
    cy.restoreLocalStorage();
    cy.visit("/");
  });

  it("accept should be visible after loading", () => {
    cy.get(ACCEPT_BUTTON).should("be.visible");
  });

  it("reject should not exist", () => {
    cy.get(REJECT_BUTTON).should("not.exist");
  });
});


================================================
FILE: test-e2e/specs/cypress/e2e/no-across-specs/save.cy.js
================================================
describe("Cookies buttons", () => {
  const ACCEPT_BUTTON = "#accept-cookies";
  const REJECT_BUTTON = "#reject-cookies";

  before(() => {
    cy.clearLocalStorageSnapshot();
  });

  beforeEach(() => {
    cy.restoreLocalStorage();
    cy.visit("/");
  });

  afterEach(() => {
    cy.saveLocalStorage();
  });

  it("accept should be visible", () => {
    cy.get(ACCEPT_BUTTON).should("be.visible");
  });

  it("accept should not be visible after clicked", () => {
    cy.get(ACCEPT_BUTTON).click();
    cy.get(ACCEPT_BUTTON).should("not.exist");
  });

  it("reject should not be visible", () => {
    cy.get(REJECT_BUTTON).should("be.visible");
  });

  it("reject should still be visible after reloading", () => {
    cy.get(REJECT_BUTTON).should("be.visible");
    cy.get(ACCEPT_BUTTON).should("not.exist");
  });
});


================================================
FILE: tsconfig.json
================================================
{
  "compilerOptions": {
    "target": "es6",
    "module": "commonjs",
    "outDir": "dist",
    "moduleResolution": "node",
    "types": ["cypress"],
    "skipLibCheck": true
  },
  "include": [
    "*.ts",
    "test-e2e/**/integration/*.ts"
  ],
  "exclude": [
    "node_modules",
    "**/node_modules"
  ]
}
Download .txt
gitextract_54gauqw_/

├── .github/
│   ├── CODE_OF_CONDUCT.md
│   ├── CONTRIBUTING.md
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.md
│   │   └── feature_request.md
│   ├── PULL_REQUEST_TEMPLATE.md
│   └── workflows/
│       ├── build.yml
│       ├── check-package-version.yml
│       ├── publish-to-github.yml
│       └── publish-to-npm.yml
├── .gitignore
├── .husky/
│   ├── .gitignore
│   └── pre-commit
├── .vscode/
│   └── settings.json
├── CHANGELOG.md
├── LICENSE
├── README.md
├── cspell/
│   └── missing.txt
├── cspell.config.js
├── eslint.config.mjs
├── index.d.ts
├── index.js
├── jest.config.js
├── package.json
├── plugin.d.ts
├── plugin.js
├── pnpm-workspace.yaml
├── renovate.json
├── sonar-project.properties
├── src/
│   ├── LocalStorage.js
│   ├── constants.js
│   ├── plugin.js
│   └── register.js
├── stryker.conf.js
├── test/
│   ├── Cy.mock.js
│   ├── Cypress.mock.js
│   ├── LocalStorage.mock.js
│   ├── LocalStorage.spec.js
│   ├── LocalStorageNode.spec.js
│   └── register.spec.js
├── test-e2e/
│   ├── app/
│   │   ├── .gitignore
│   │   ├── package.json
│   │   ├── public/
│   │   │   └── index.html
│   │   ├── serve.json
│   │   └── src/
│   │       ├── App.css
│   │       ├── App.js
│   │       ├── components/
│   │       │   ├── cookies-button/
│   │       │   │   ├── CookiesButton.css
│   │       │   │   ├── CookiesButton.js
│   │       │   │   └── index.js
│   │       │   └── cookies-value/
│   │       │       ├── CookiesValue.js
│   │       │       └── index.js
│   │       ├── data/
│   │       │   └── user-preferences/
│   │       │       ├── actions.js
│   │       │       ├── index.js
│   │       │       ├── origins.js
│   │       │       └── selectors.js
│   │       ├── index.css
│   │       ├── index.js
│   │       └── modules/
│   │           ├── accept-cookies/
│   │           │   ├── AcceptCookies.js
│   │           │   └── index.js
│   │           ├── cookies-value/
│   │           │   ├── CookiesValue.js
│   │           │   └── index.js
│   │           ├── localstorage-warning/
│   │           │   ├── LocalStorageWarning.css
│   │           │   ├── LocalStorageWarning.js
│   │           │   └── index.js
│   │           └── reject-cookies/
│   │               ├── RejectCookies.js
│   │               └── index.js
│   ├── cypress-14/
│   │   ├── .gitignore
│   │   ├── babel.config.js
│   │   ├── cypress/
│   │   │   ├── plugins/
│   │   │   │   └── index.js
│   │   │   └── support/
│   │   │       ├── commands.js
│   │   │       └── e2e.js
│   │   ├── cypress.config.js
│   │   └── package.json
│   ├── cypress-14-no-plugin/
│   │   ├── .gitignore
│   │   ├── babel.config.js
│   │   ├── cypress/
│   │   │   ├── plugins/
│   │   │   │   └── index.js
│   │   │   └── support/
│   │   │       ├── commands.js
│   │   │       └── e2e.js
│   │   ├── cypress.config.js
│   │   └── package.json
│   ├── cypress-9/
│   │   ├── .gitignore
│   │   ├── babel.config.js
│   │   ├── cypress/
│   │   │   ├── .eslintrc.json
│   │   │   ├── plugins/
│   │   │   │   └── index.js
│   │   │   └── support/
│   │   │       ├── commands.js
│   │   │       └── index.js
│   │   ├── cypress.config.js
│   │   ├── package.json
│   │   └── scripts/
│   │       └── copySpecs.js
│   ├── cypress-9-no-plugin/
│   │   ├── .gitignore
│   │   ├── babel.config.js
│   │   ├── cypress/
│   │   │   ├── .eslintrc.json
│   │   │   ├── plugins/
│   │   │   │   └── index.js
│   │   │   └── support/
│   │   │       ├── commands.js
│   │   │       └── index.js
│   │   ├── cypress.config.js
│   │   ├── package.json
│   │   └── scripts/
│   │       └── copySpecs.js
│   ├── cypress-latest/
│   │   ├── .gitignore
│   │   ├── babel.config.js
│   │   ├── cypress/
│   │   │   ├── plugins/
│   │   │   │   └── index.js
│   │   │   └── support/
│   │   │       ├── commands.js
│   │   │       └── e2e.js
│   │   ├── cypress.config.js
│   │   └── package.json
│   ├── cypress-latest-no-plugin/
│   │   ├── .gitignore
│   │   ├── babel.config.js
│   │   ├── cypress/
│   │   │   ├── plugins/
│   │   │   │   └── index.js
│   │   │   └── support/
│   │   │       ├── commands.js
│   │   │       └── e2e.js
│   │   ├── cypress.config.js
│   │   └── package.json
│   ├── cypress-typescript/
│   │   ├── .eslintignore
│   │   ├── .gitignore
│   │   ├── cypress/
│   │   │   ├── e2e/
│   │   │   │   ├── assertions-example.cy.ts
│   │   │   │   ├── cookies-example.cy.ts
│   │   │   │   ├── cookies.cy.ts
│   │   │   │   ├── localstorage-disabled.cy.ts
│   │   │   │   └── named-snapshots.cy.ts
│   │   │   └── support/
│   │   │       ├── commands.js
│   │   │       └── e2e.js
│   │   ├── cypress.config.ts
│   │   ├── package.json
│   │   ├── scripts/
│   │   │   └── copyLibrary.js
│   │   └── tsconfig.json
│   └── specs/
│       └── cypress/
│           └── e2e/
│               ├── across-specs/
│               │   ├── restore.cy.js
│               │   └── save.cy.js
│               ├── assertions-example.cy.js
│               ├── cookies-example.cy.js
│               ├── cookies.cy.js
│               ├── localstorage-disabled.cy.js
│               ├── named-across-specs/
│               │   ├── restore-after-clear.cy.js
│               │   ├── restore.cy.js
│               │   └── save.cy.js
│               ├── named-snapshots.cy.js
│               └── no-across-specs/
│                   ├── restore.cy.js
│                   └── save.cy.js
└── tsconfig.json
Download .txt
SYMBOL INDEX (58 symbols across 16 files)

FILE: cspell.config.js
  constant DICTIONARIES_BASE_PATH (line 3) | const DICTIONARIES_BASE_PATH = resolve(__dirname, "cspell");

FILE: index.d.ts
  type Chainable (line 4) | interface Chainable {

FILE: src/LocalStorage.js
  constant LOCAL_STORAGE_METHODS (line 8) | const LOCAL_STORAGE_METHODS = ["setItem", "getItem", "removeItem", "clea...
  function logDisabled (line 10) | function logDisabled(method) {
  function logDisabledMethodName (line 16) | function logDisabledMethodName(localStorageMethod) {
  class LocalStorage (line 20) | class LocalStorage {
    method cypressCommands (line 21) | static get cypressCommands() {
    method constructor (line 33) | constructor(localStorage, cy, Cypress) {
    method _saveLocalStorageKeyToMemory (line 49) | _saveLocalStorageKeyToMemory(key, snapshotName) {
    method _saveLocalStorageToMemory (line 57) | _saveLocalStorageToMemory(snapshotName) {
    method _clearMemorySnapshot (line 63) | _clearMemorySnapshot(snapshotName) {
    method _getSnapshotFromMemory (line 71) | _getSnapshotFromMemory(snapshotName) {
    method _restoreLocalStorageFromSnapshot (line 75) | _restoreLocalStorageFromSnapshot(obj = {}) {
    method _restoreLocalStorageFromMemory (line 81) | _restoreLocalStorageFromMemory(snapshotName) {
    method _copySnapshotFromMemoryToNode (line 87) | _copySnapshotFromMemoryToNode(snapshotName) {
    method _clearNodeSnapshot (line 96) | _clearNodeSnapshot(snapshotName) {
    method _restoreLocalStorageFromNode (line 102) | _restoreLocalStorageFromNode(snapshotName) {
    method clearLocalStorageSnapshot (line 108) | clearLocalStorageSnapshot(snapshotName) {
    method saveLocalStorage (line 113) | saveLocalStorage(snapshotName) {
    method restoreLocalStorage (line 121) | restoreLocalStorage(snapshotName) {
    method getLocalStorage (line 130) | getLocalStorage(key) {
    method setLocalStorage (line 134) | setLocalStorage(key, value) {
    method removeLocalStorage (line 138) | removeLocalStorage(key) {
    method disableLocalStorage (line 142) | disableLocalStorage(options = {}) {

FILE: src/constants.js
  constant GET_SNAPSHOT_TASK (line 1) | const GET_SNAPSHOT_TASK = "cypressLocalStorageGetSnapshot";
  constant SET_SNAPSHOT_TASK (line 2) | const SET_SNAPSHOT_TASK = "cypressLocalStorageSetSnapshot";
  constant CLEAR_SNAPSHOT_TASK (line 3) | const CLEAR_SNAPSHOT_TASK = "cypressLocalStorageClearSnapshot";
  constant NODE_EVENTS_INSTALLED (line 4) | const NODE_EVENTS_INSTALLED = "LOCALSTORAGE_NODE_EVENTS_INSTALLED";

FILE: stryker.conf.js
  constant BRANCH_NAME (line 1) | const BRANCH_NAME = process.env.BRANCH_NAME;
  constant STRYKER_DASHBOARD_API_KEY (line 2) | const STRYKER_DASHBOARD_API_KEY = process.env.STRYKER_DASHBOARD_API_KEY;
  constant BASE_CONFIG (line 4) | const BASE_CONFIG = {

FILE: test-e2e/app/src/App.js
  function App (line 19) | function App() {

FILE: test-e2e/app/src/data/user-preferences/actions.js
  function log (line 3) | function log(...args) {

FILE: test-e2e/cypress-14-no-plugin/cypress.config.js
  method setupNodeEvents (line 7) | setupNodeEvents(on) {

FILE: test-e2e/cypress-14/cypress.config.js
  method setupNodeEvents (line 7) | setupNodeEvents(on, config) {

FILE: test-e2e/cypress-latest-no-plugin/cypress.config.js
  method setupNodeEvents (line 7) | setupNodeEvents(on) {

FILE: test-e2e/cypress-latest/cypress.config.js
  method setupNodeEvents (line 7) | setupNodeEvents(on, config) {

FILE: test-e2e/cypress-typescript/cypress.config.ts
  method setupNodeEvents (line 7) | setupNodeEvents(on, config) {

FILE: test-e2e/cypress-typescript/scripts/copyLibrary.js
  constant SRC_FOLDER (line 13) | const SRC_FOLDER = "src";
  constant INDEX_FILE (line 14) | const INDEX_FILE = "index.js";
  constant INDEX_TS_FILE (line 15) | const INDEX_TS_FILE = "index.d.ts";
  constant PLUGIN_FILE (line 16) | const PLUGIN_FILE = "plugin.js";
  constant PLUGIN_TS_FILE (line 17) | const PLUGIN_TS_FILE = "plugin.d.ts";

FILE: test/Cy.mock.js
  class Cy (line 7) | class Cy {
    method constructor (line 8) | constructor() {
    method stubs (line 30) | get stubs() {
    method restore (line 34) | restore() {
    method reset (line 38) | reset() {
    method loadWindow (line 42) | loadWindow() {
    method window (line 46) | get window() {

FILE: test/Cypress.mock.js
  method constructor (line 4) | constructor() {
  method stubs (line 16) | get stubs() {
  method restore (line 20) | restore() {

FILE: test/LocalStorage.mock.js
  constant LOCALSTORAGE_METHODS (line 3) | const LOCALSTORAGE_METHODS = new Set([
  method constructor (line 11) | constructor() {
  method stubs (line 36) | get stubs() {
  method restore (line 40) | restore() {
  method reset (line 44) | reset() {
Condensed preview — 137 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (161K chars).
[
  {
    "path": ".github/CODE_OF_CONDUCT.md",
    "chars": 3193,
    "preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, w"
  },
  {
    "path": ".github/CONTRIBUTING.md",
    "chars": 5111,
    "preview": "# Contributing\n\nFirst off, thanks for taking the time to contribute!\n\nThe following is a set of guidelines for contribut"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "chars": 636,
    "preview": "---\nname: Bug report\nabout: Create a report to help us improve\n\n---\n\n**Describe the bug**\nA clear and concise descriptio"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "chars": 557,
    "preview": "---\nname: Feature request\nabout: Suggest an idea for this project\n\n---\n\n**Is your feature request related to a problem? "
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "chars": 485,
    "preview": "**IMPORTANT: Please do not create a Pull Request without creating an issue first.**\n\n*Any change needs to be discussed b"
  },
  {
    "path": ".github/workflows/build.yml",
    "chars": 2967,
    "preview": "name: build\non:\n  push:\n    branches:\n      - master\n      - release\n  pull_request:\nconcurrency:  \n  group: ${{ github."
  },
  {
    "path": ".github/workflows/check-package-version.yml",
    "chars": 1447,
    "preview": "name: check-package-version\non:\n  pull_request:\n    branches:\n      - master\njobs:\n  check-package-version:\n    runs-on:"
  },
  {
    "path": ".github/workflows/publish-to-github.yml",
    "chars": 940,
    "preview": "name: publish-to-github\non:\n  release:\n    types: [created]\njobs:\n  publish:\n    runs-on: ubuntu-latest\n    steps:\n    -"
  },
  {
    "path": ".github/workflows/publish-to-npm.yml",
    "chars": 567,
    "preview": "name: publish-to-npm\non:\n  release:\n    types: [created]\njobs:\n  publish:\n    runs-on: ubuntu-latest\n    steps:\n    - na"
  },
  {
    "path": ".gitignore",
    "chars": 405,
    "preview": "# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n#environment variables\n/.env\n\n# dependencies"
  },
  {
    "path": ".husky/.gitignore",
    "chars": 2,
    "preview": "_\n"
  },
  {
    "path": ".husky/pre-commit",
    "chars": 21,
    "preview": "pnpm run lint-staged\n"
  },
  {
    "path": ".vscode/settings.json",
    "chars": 146,
    "preview": "{\n  \"sonarlint.connectedMode.project\": {\n      \"connectionId\": \"javierbrea\",\n      \"projectKey\": \"javierbrea_cypress-loc"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 8079,
    "preview": "# Change Log\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Change"
  },
  {
    "path": "LICENSE",
    "chars": 1073,
    "preview": "MIT License\n\nCopyright (c) 2019-2024 Javier Brea\n\nPermission is hereby granted, free of charge, to any person obtaining "
  },
  {
    "path": "README.md",
    "chars": 13242,
    "preview": "[![Build status][build-image]][build-url] [![Coverage Status][coveralls-image]][coveralls-url] [![Quality Gate][quality-"
  },
  {
    "path": "cspell/missing.txt",
    "chars": 96,
    "preview": "Brea\ncommonmark\ncoverallsapp\njavierbrea\nMerthin\nprelint\nsonarcloud\nsonarqube\nsonarsource\nUninen\n"
  },
  {
    "path": "cspell.config.js",
    "chars": 1377,
    "preview": "const { resolve } = require(\"node:path\");\n\nconst DICTIONARIES_BASE_PATH = resolve(__dirname, \"cspell\");\n\nmodule.exports "
  },
  {
    "path": "eslint.config.mjs",
    "chars": 4483,
    "preview": "import json from \"@eslint/json\";\nimport markdown from \"@eslint/markdown\";\nimport prettier from \"eslint-plugin-prettier\";"
  },
  {
    "path": "index.d.ts",
    "chars": 1926,
    "preview": "/// <reference types=\"cypress\" />\n\ndeclare namespace Cypress {\n  interface Chainable {\n    /**\n     * Command to save cu"
  },
  {
    "path": "index.js",
    "chars": 126,
    "preview": "/* global Cypress, cy, localStorage */\n\nconst { register } = require(\"./src/register\");\n\nregister(Cypress, cy, localStor"
  },
  {
    "path": "jest.config.js",
    "chars": 990,
    "preview": "// For a detailed explanation regarding each configuration property, visit:\n// https://jestjs.io/docs/en/configuration.h"
  },
  {
    "path": "package.json",
    "chars": 3142,
    "preview": "{\n  \"name\": \"cypress-localstorage-commands\",\n  \"version\": \"2.3.0\",\n  \"description\": \"Extends Cypress' cy commands with l"
  },
  {
    "path": "plugin.d.ts",
    "chars": 398,
    "preview": "/// <reference types=\"cypress\" />\n\n/**\n * Installs cypress-localstorage-commands node events\n * @example plugin(on, conf"
  },
  {
    "path": "plugin.js",
    "chars": 42,
    "preview": "module.exports = require(\"./src/plugin\");\n"
  },
  {
    "path": "pnpm-workspace.yaml",
    "chars": 62,
    "preview": "packages:\n  - \".\"\n  - \"test-e2e/app\"\n  - \"test-e2e/cypress-*\"\n"
  },
  {
    "path": "renovate.json",
    "chars": 683,
    "preview": "{\n  \"extends\": [\n    \"github>javierbrea/renovate-config\"\n  ],\n  \"packageRules\": [\n    {\n      \"matchPaths\": [\"test-e2e/c"
  },
  {
    "path": "sonar-project.properties",
    "chars": 516,
    "preview": "sonar.organization=javierbrea\nsonar.projectKey=javierbrea_cypress-localstorage-commands\nsonar.projectVersion=2.3.0\n\nsona"
  },
  {
    "path": "src/LocalStorage.js",
    "chars": 4377,
    "preview": "const {\n  GET_SNAPSHOT_TASK,\n  SET_SNAPSHOT_TASK,\n  CLEAR_SNAPSHOT_TASK,\n  NODE_EVENTS_INSTALLED,\n} = require(\"./constan"
  },
  {
    "path": "src/constants.js",
    "chars": 365,
    "preview": "const GET_SNAPSHOT_TASK = \"cypressLocalStorageGetSnapshot\";\nconst SET_SNAPSHOT_TASK = \"cypressLocalStorageSetSnapshot\";\n"
  },
  {
    "path": "src/plugin.js",
    "chars": 973,
    "preview": "const {\n  GET_SNAPSHOT_TASK,\n  SET_SNAPSHOT_TASK,\n  CLEAR_SNAPSHOT_TASK,\n  NODE_EVENTS_INSTALLED,\n} = require(\"./constan"
  },
  {
    "path": "src/register.js",
    "chars": 421,
    "preview": "const LocalStorage = require(\"./LocalStorage\");\n\nconst register = (Cypress, cy, localStorage) => {\n  const localStorageC"
  },
  {
    "path": "stryker.conf.js",
    "chars": 724,
    "preview": "const BRANCH_NAME = process.env.BRANCH_NAME;\nconst STRYKER_DASHBOARD_API_KEY = process.env.STRYKER_DASHBOARD_API_KEY;\n\nc"
  },
  {
    "path": "test/Cy.mock.js",
    "chars": 856,
    "preview": "const sinon = require(\"sinon\");\n\nconst doNothing = () => {\n  // do nothing\n};\n\nclass Cy {\n  constructor() {\n    this._sa"
  },
  {
    "path": "test/Cypress.mock.js",
    "chars": 403,
    "preview": "const sinon = require(\"sinon\");\n\nconst Mock = class Mock {\n  constructor() {\n    this._sandbox = sinon.createSandbox();\n"
  },
  {
    "path": "test/LocalStorage.mock.js",
    "chars": 1005,
    "preview": "const sinon = require(\"sinon\");\n\nconst LOCALSTORAGE_METHODS = new Set([\n  \"getItem\",\n  \"setItem\",\n  \"removeItem\",\n  \"cle"
  },
  {
    "path": "test/LocalStorage.spec.js",
    "chars": 13529,
    "preview": "const LocalStorageMock = require(\"./LocalStorage.mock\");\nconst CyMock = require(\"./Cy.mock\");\nconst CypressMock = requir"
  },
  {
    "path": "test/LocalStorageNode.spec.js",
    "chars": 9525,
    "preview": "const LocalStorageMock = require(\"./LocalStorage.mock\");\nconst CyMock = require(\"./Cy.mock\");\nconst CypressMock = requir"
  },
  {
    "path": "test/register.spec.js",
    "chars": 1331,
    "preview": "const LocalStorageMock = require(\"./LocalStorage.mock\");\nconst CypressMock = require(\"./Cypress.mock\");\n\nconst LocalStor"
  },
  {
    "path": "test-e2e/app/.gitignore",
    "chars": 329,
    "preview": "# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n#environment variables\n#.env\n\n# dependencies"
  },
  {
    "path": "test-e2e/app/package.json",
    "chars": 871,
    "preview": "{\n  \"name\": \"app\",\n  \"private\": true,\n  \"dependencies\": {\n    \"@data-provider/browser-storage\": \"4.0.0\",\n    \"@data-prov"
  },
  {
    "path": "test-e2e/app/public/index.html",
    "chars": 444,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "test-e2e/app/serve.json",
    "chars": 189,
    "preview": "{\n  \"public\": \"build\",\n  \"trailingSlash\": false,\n  \"directoryListing\": false,\n  \"cleanUrls\": true,\n  \"rewrites\": [\n    {"
  },
  {
    "path": "test-e2e/app/src/App.css",
    "chars": 240,
    "preview": ".App {\n  text-align: center;\n}\n\n.App-header {\n  background-color: #282c34;\n  min-height: 100vh;\n  display: flex;\n  flex-"
  },
  {
    "path": "test-e2e/app/src/App.js",
    "chars": 1029,
    "preview": "import { Provider } from \"react-redux\";\nimport { createStore, combineReducers } from \"redux\";\nimport { storeManager } fr"
  },
  {
    "path": "test-e2e/app/src/components/cookies-button/CookiesButton.css",
    "chars": 389,
    "preview": "button.cookies-button {\n  color: #09d3ac;\n  padding: 10px;\n  font-size: 20px;\n  border: 1px solid #09d3ac;\n  background-"
  },
  {
    "path": "test-e2e/app/src/components/cookies-button/CookiesButton.js",
    "chars": 509,
    "preview": "import PropTypes from \"prop-types\";\n\nimport \"./CookiesButton.css\";\n\nexport const CookiesButton = ({ visible, onClick, id"
  },
  {
    "path": "test-e2e/app/src/components/cookies-button/index.js",
    "chars": 60,
    "preview": "export { CookiesButton as default } from \"./CookiesButton\";\n"
  },
  {
    "path": "test-e2e/app/src/components/cookies-value/CookiesValue.js",
    "chars": 279,
    "preview": "import PropTypes from \"prop-types\";\n\nexport const CookiesValue = ({ value }) => {\n  return (\n    <p>\n      Cookies are c"
  },
  {
    "path": "test-e2e/app/src/components/cookies-value/index.js",
    "chars": 58,
    "preview": "export { CookiesValue as default } from \"./CookiesValue\";\n"
  },
  {
    "path": "test-e2e/app/src/data/user-preferences/actions.js",
    "chars": 962,
    "preview": "import { userPreferences } from \"./origins\";\n\nfunction log(...args) {\n  // eslint-disable-next-line no-console\n  console"
  },
  {
    "path": "test-e2e/app/src/data/user-preferences/index.js",
    "chars": 83,
    "preview": "export * from \"./origins\";\nexport * from \"./selectors\";\nexport * from \"./actions\";\n"
  },
  {
    "path": "test-e2e/app/src/data/user-preferences/origins.js",
    "chars": 256,
    "preview": "import { LocalStorage } from \"@data-provider/browser-storage\";\n\nexport const userPreferences = new LocalStorage({\n  id: "
  },
  {
    "path": "test-e2e/app/src/data/user-preferences/selectors.js",
    "chars": 225,
    "preview": "import { Selector } from \"@data-provider/core\";\n\nimport { userPreferences } from \"./origins\";\n\nexport const cookiesAccep"
  },
  {
    "path": "test-e2e/app/src/index.css",
    "chars": 269,
    "preview": "body {\n  margin: 0;\n  font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Roboto\", \"Oxygen\",\n    \"Ubuntu\", \"Can"
  },
  {
    "path": "test-e2e/app/src/index.js",
    "chars": 141,
    "preview": "import ReactDOM from \"react-dom\";\nimport \"./index.css\";\nimport App from \"./App\";\n\nReactDOM.render(<App />, document.getE"
  },
  {
    "path": "test-e2e/app/src/modules/accept-cookies/AcceptCookies.js",
    "chars": 528,
    "preview": "import { useData, useError } from \"@data-provider/react\";\n\nimport CookiesButton from \"../../components/cookies-button\";\n"
  },
  {
    "path": "test-e2e/app/src/modules/accept-cookies/index.js",
    "chars": 43,
    "preview": "export { default } from \"./AcceptCookies\";\n"
  },
  {
    "path": "test-e2e/app/src/modules/cookies-value/CookiesValue.js",
    "chars": 238,
    "preview": "import { withData } from \"@data-provider/react\";\n\nimport CookiesValue from \"../../components/cookies-value\";\nimport { co"
  },
  {
    "path": "test-e2e/app/src/modules/cookies-value/index.js",
    "chars": 42,
    "preview": "export { default } from \"./CookiesValue\";\n"
  },
  {
    "path": "test-e2e/app/src/modules/localstorage-warning/LocalStorageWarning.css",
    "chars": 53,
    "preview": "#localstorage-disabled-warning {\n  color: #ff9900;\n}\n"
  },
  {
    "path": "test-e2e/app/src/modules/localstorage-warning/LocalStorageWarning.js",
    "chars": 492,
    "preview": "import { useError } from \"@data-provider/react\";\n\nimport { cookiesAccepted } from \"../../data/user-preferences\";\n\nimport"
  },
  {
    "path": "test-e2e/app/src/modules/localstorage-warning/index.js",
    "chars": 49,
    "preview": "export { default } from \"./LocalStorageWarning\";\n"
  },
  {
    "path": "test-e2e/app/src/modules/reject-cookies/RejectCookies.js",
    "chars": 447,
    "preview": "import { useData } from \"@data-provider/react\";\n\nimport CookiesButton from \"../../components/cookies-button\";\nimport { c"
  },
  {
    "path": "test-e2e/app/src/modules/reject-cookies/index.js",
    "chars": 43,
    "preview": "export { default } from \"./RejectCookies\";\n"
  },
  {
    "path": "test-e2e/cypress-14/.gitignore",
    "chars": 378,
    "preview": "# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n#environment variables\n#.env\n\n# dependencies"
  },
  {
    "path": "test-e2e/cypress-14/babel.config.js",
    "chars": 197,
    "preview": "module.exports = {\n  plugins: [\n    [\n      \"module-resolver\",\n      {\n        root: [\".\"],\n        alias: {\n          \""
  },
  {
    "path": "test-e2e/cypress-14/cypress/plugins/index.js",
    "chars": 800,
    "preview": "/// <reference types=\"cypress\" />\n// ***********************************************************\n// This example plugins"
  },
  {
    "path": "test-e2e/cypress-14/cypress/support/commands.js",
    "chars": 89,
    "preview": "// eslint-disable-next-line import/no-unresolved\nimport \"cypress-localstorage-commands\";\n"
  },
  {
    "path": "test-e2e/cypress-14/cypress/support/e2e.js",
    "chars": 21,
    "preview": "import \"./commands\";\n"
  },
  {
    "path": "test-e2e/cypress-14/cypress.config.js",
    "chars": 835,
    "preview": "const webpackPreprocessor = require(\"@cypress/webpack-preprocessor\");\nconst defaults = webpackPreprocessor.defaultOption"
  },
  {
    "path": "test-e2e/cypress-14/package.json",
    "chars": 415,
    "preview": "{\n  \"name\": \"cypress-14\",\n  \"private\": true,\n  \"scripts\": {\n    \"build:serve\": \"cd ../app && pnpm run build:serve\",\n    "
  },
  {
    "path": "test-e2e/cypress-14-no-plugin/.gitignore",
    "chars": 378,
    "preview": "# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n#environment variables\n#.env\n\n# dependencies"
  },
  {
    "path": "test-e2e/cypress-14-no-plugin/babel.config.js",
    "chars": 197,
    "preview": "module.exports = {\n  plugins: [\n    [\n      \"module-resolver\",\n      {\n        root: [\".\"],\n        alias: {\n          \""
  },
  {
    "path": "test-e2e/cypress-14-no-plugin/cypress/plugins/index.js",
    "chars": 800,
    "preview": "/// <reference types=\"cypress\" />\n// ***********************************************************\n// This example plugins"
  },
  {
    "path": "test-e2e/cypress-14-no-plugin/cypress/support/commands.js",
    "chars": 89,
    "preview": "// eslint-disable-next-line import/no-unresolved\nimport \"cypress-localstorage-commands\";\n"
  },
  {
    "path": "test-e2e/cypress-14-no-plugin/cypress/support/e2e.js",
    "chars": 21,
    "preview": "import \"./commands\";\n"
  },
  {
    "path": "test-e2e/cypress-14-no-plugin/cypress.config.js",
    "chars": 567,
    "preview": "const webpackPreprocessor = require(\"@cypress/webpack-preprocessor\");\nconst defaults = webpackPreprocessor.defaultOption"
  },
  {
    "path": "test-e2e/cypress-14-no-plugin/package.json",
    "chars": 425,
    "preview": "{\n  \"name\": \"cypress-14-no-plugin\",\n  \"private\": true,\n  \"scripts\": {\n    \"build:serve\": \"cd ../app && pnpm run build:se"
  },
  {
    "path": "test-e2e/cypress-9/.gitignore",
    "chars": 399,
    "preview": "# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n#environment variables\n#.env\n\n# dependencies"
  },
  {
    "path": "test-e2e/cypress-9/babel.config.js",
    "chars": 197,
    "preview": "module.exports = {\n  plugins: [\n    [\n      \"module-resolver\",\n      {\n        root: [\".\"],\n        alias: {\n          \""
  },
  {
    "path": "test-e2e/cypress-9/cypress/.eslintrc.json",
    "chars": 232,
    "preview": "{\n  \"env\": {\n    \"node\": true,\n    \"es6\": true\n  },\n  \"globals\": {\n    \"cy\": true,\n    \"afterEach\": true,\n    \"after\": t"
  },
  {
    "path": "test-e2e/cypress-9/cypress/plugins/index.js",
    "chars": 421,
    "preview": "const webpackPreprocessor = require(\"@cypress/webpack-preprocessor\");\nconst defaults = webpackPreprocessor.defaultOption"
  },
  {
    "path": "test-e2e/cypress-9/cypress/support/commands.js",
    "chars": 89,
    "preview": "// eslint-disable-next-line import/no-unresolved\nimport \"cypress-localstorage-commands\";\n"
  },
  {
    "path": "test-e2e/cypress-9/cypress/support/index.js",
    "chars": 21,
    "preview": "import \"./commands\";\n"
  },
  {
    "path": "test-e2e/cypress-9/cypress.config.js",
    "chars": 303,
    "preview": "module.exports = {\n  baseUrl: \"http://localhost:3000\",\n  video: false,\n  testFiles: [\n    \"*.cy.js\",\n    \"across-specs/s"
  },
  {
    "path": "test-e2e/cypress-9/package.json",
    "chars": 558,
    "preview": "{\n  \"name\": \"cypress-9\",\n  \"private\": true,\n  \"scripts\": {\n    \"build:serve\": \"cd ../app && pnpm run build:serve\",\n    \""
  },
  {
    "path": "test-e2e/cypress-9/scripts/copySpecs.js",
    "chars": 376,
    "preview": "const path = require(\"node:path\");\nconst fsExtra = require(\"fs-extra\");\n\nconst rootPath = path.resolve(__dirname, \"..\");"
  },
  {
    "path": "test-e2e/cypress-9-no-plugin/.gitignore",
    "chars": 399,
    "preview": "# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n#environment variables\n#.env\n\n# dependencies"
  },
  {
    "path": "test-e2e/cypress-9-no-plugin/babel.config.js",
    "chars": 197,
    "preview": "module.exports = {\n  plugins: [\n    [\n      \"module-resolver\",\n      {\n        root: [\".\"],\n        alias: {\n          \""
  },
  {
    "path": "test-e2e/cypress-9-no-plugin/cypress/.eslintrc.json",
    "chars": 232,
    "preview": "{\n  \"env\": {\n    \"node\": true,\n    \"es6\": true\n  },\n  \"globals\": {\n    \"cy\": true,\n    \"afterEach\": true,\n    \"after\": t"
  },
  {
    "path": "test-e2e/cypress-9-no-plugin/cypress/plugins/index.js",
    "chars": 352,
    "preview": "const webpackPreprocessor = require(\"@cypress/webpack-preprocessor\");\nconst defaults = webpackPreprocessor.defaultOption"
  },
  {
    "path": "test-e2e/cypress-9-no-plugin/cypress/support/commands.js",
    "chars": 89,
    "preview": "// eslint-disable-next-line import/no-unresolved\nimport \"cypress-localstorage-commands\";\n"
  },
  {
    "path": "test-e2e/cypress-9-no-plugin/cypress/support/index.js",
    "chars": 21,
    "preview": "import \"./commands\";\n"
  },
  {
    "path": "test-e2e/cypress-9-no-plugin/cypress.config.js",
    "chars": 180,
    "preview": "module.exports = {\n  baseUrl: \"http://localhost:3000\",\n  video: false,\n  testFiles: [\n    \"*.cy.js\",\n    \"no-across-spec"
  },
  {
    "path": "test-e2e/cypress-9-no-plugin/package.json",
    "chars": 568,
    "preview": "{\n  \"name\": \"cypress-9-no-plugin\",\n  \"private\": true,\n  \"scripts\": {\n    \"build:serve\": \"cd ../app && pnpm run build:ser"
  },
  {
    "path": "test-e2e/cypress-9-no-plugin/scripts/copySpecs.js",
    "chars": 376,
    "preview": "const path = require(\"node:path\");\nconst fsExtra = require(\"fs-extra\");\n\nconst rootPath = path.resolve(__dirname, \"..\");"
  },
  {
    "path": "test-e2e/cypress-latest/.gitignore",
    "chars": 378,
    "preview": "# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n#environment variables\n#.env\n\n# dependencies"
  },
  {
    "path": "test-e2e/cypress-latest/babel.config.js",
    "chars": 197,
    "preview": "module.exports = {\n  plugins: [\n    [\n      \"module-resolver\",\n      {\n        root: [\".\"],\n        alias: {\n          \""
  },
  {
    "path": "test-e2e/cypress-latest/cypress/plugins/index.js",
    "chars": 800,
    "preview": "/// <reference types=\"cypress\" />\n// ***********************************************************\n// This example plugins"
  },
  {
    "path": "test-e2e/cypress-latest/cypress/support/commands.js",
    "chars": 89,
    "preview": "// eslint-disable-next-line import/no-unresolved\nimport \"cypress-localstorage-commands\";\n"
  },
  {
    "path": "test-e2e/cypress-latest/cypress/support/e2e.js",
    "chars": 21,
    "preview": "import \"./commands\";\n"
  },
  {
    "path": "test-e2e/cypress-latest/cypress.config.js",
    "chars": 861,
    "preview": "const webpackPreprocessor = require(\"@cypress/webpack-preprocessor\");\nconst defaults = webpackPreprocessor.defaultOption"
  },
  {
    "path": "test-e2e/cypress-latest/package.json",
    "chars": 420,
    "preview": "{\n  \"name\": \"cypress-latest\",\n  \"private\": true,\n  \"scripts\": {\n    \"build:serve\": \"cd ../app && pnpm run build:serve\",\n"
  },
  {
    "path": "test-e2e/cypress-latest-no-plugin/.gitignore",
    "chars": 378,
    "preview": "# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n#environment variables\n#.env\n\n# dependencies"
  },
  {
    "path": "test-e2e/cypress-latest-no-plugin/babel.config.js",
    "chars": 197,
    "preview": "module.exports = {\n  plugins: [\n    [\n      \"module-resolver\",\n      {\n        root: [\".\"],\n        alias: {\n          \""
  },
  {
    "path": "test-e2e/cypress-latest-no-plugin/cypress/plugins/index.js",
    "chars": 800,
    "preview": "/// <reference types=\"cypress\" />\n// ***********************************************************\n// This example plugins"
  },
  {
    "path": "test-e2e/cypress-latest-no-plugin/cypress/support/commands.js",
    "chars": 89,
    "preview": "// eslint-disable-next-line import/no-unresolved\nimport \"cypress-localstorage-commands\";\n"
  },
  {
    "path": "test-e2e/cypress-latest-no-plugin/cypress/support/e2e.js",
    "chars": 21,
    "preview": "import \"./commands\";\n"
  },
  {
    "path": "test-e2e/cypress-latest-no-plugin/cypress.config.js",
    "chars": 593,
    "preview": "const webpackPreprocessor = require(\"@cypress/webpack-preprocessor\");\nconst defaults = webpackPreprocessor.defaultOption"
  },
  {
    "path": "test-e2e/cypress-latest-no-plugin/package.json",
    "chars": 430,
    "preview": "{\n  \"name\": \"cypress-latest-no-plugin\",\n  \"private\": true,\n  \"scripts\": {\n    \"build:serve\": \"cd ../app && pnpm run buil"
  },
  {
    "path": "test-e2e/cypress-typescript/.eslintignore",
    "chars": 13,
    "preview": "/node_modules"
  },
  {
    "path": "test-e2e/cypress-typescript/.gitignore",
    "chars": 443,
    "preview": "# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n#environment variables\n#.env\n\n# dependencies"
  },
  {
    "path": "test-e2e/cypress-typescript/cypress/e2e/assertions-example.cy.ts",
    "chars": 915,
    "preview": "// Next reference is commented as package is not available at node_modules\n//// <reference types=\"cypress-localstorage-c"
  },
  {
    "path": "test-e2e/cypress-typescript/cypress/e2e/cookies-example.cy.ts",
    "chars": 1426,
    "preview": "// Next reference is commented as package is not available at node_modules\n//// <reference types=\"cypress-localstorage-c"
  },
  {
    "path": "test-e2e/cypress-typescript/cypress/e2e/cookies.cy.ts",
    "chars": 8789,
    "preview": "// Next reference is commented as package is not available at node_modules\n//// <reference types=\"cypress-localstorage-c"
  },
  {
    "path": "test-e2e/cypress-typescript/cypress/e2e/localstorage-disabled.cy.ts",
    "chars": 775,
    "preview": "// Next reference is commented as package is not available at node_modules\n//// <reference types=\"cypress-localstorage-c"
  },
  {
    "path": "test-e2e/cypress-typescript/cypress/e2e/named-snapshots.cy.ts",
    "chars": 1298,
    "preview": "// Next reference is commented as package is not available at node_modules\n//// <reference types=\"cypress-localstorage-c"
  },
  {
    "path": "test-e2e/cypress-typescript/cypress/support/commands.js",
    "chars": 91,
    "preview": "// eslint-disable-next-line import/no-unresolved\nimport \"./cypress-localstorage-commands\";\n"
  },
  {
    "path": "test-e2e/cypress-typescript/cypress/support/e2e.js",
    "chars": 136,
    "preview": "// Import commands.js using ES2015 syntax:\nimport \"./commands\";\n\n// Alternatively you can use CommonJS syntax:\n// requir"
  },
  {
    "path": "test-e2e/cypress-typescript/cypress.config.ts",
    "chars": 331,
    "preview": "// eslint-disable-next-line @typescript-eslint/no-require-imports\nimport plugin = require(\"./cypress/support/cypress-loc"
  },
  {
    "path": "test-e2e/cypress-typescript/package.json",
    "chars": 675,
    "preview": "{\n  \"name\": \"cypress-typescript\",\n  \"version\": \"1.0.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"prelint\": \"pnpm run copy:"
  },
  {
    "path": "test-e2e/cypress-typescript/scripts/copyLibrary.js",
    "chars": 1201,
    "preview": "const path = require(\"node:path\");\nconst fsExtra = require(\"fs-extra\");\n\nconst rootPath = path.resolve(__dirname, \"..\");"
  },
  {
    "path": "test-e2e/cypress-typescript/tsconfig.json",
    "chars": 230,
    "preview": "{\n  \"compilerOptions\": {\n    \"target\": \"es6\",\n    \"module\": \"commonjs\",\n    \"outDir\": \"dist\",\n    \"moduleResolution\": \"n"
  },
  {
    "path": "test-e2e/specs/cypress/e2e/across-specs/restore.cy.js",
    "chars": 412,
    "preview": "describe(\"Cookies buttons\", () => {\n  const ACCEPT_BUTTON = \"#accept-cookies\";\n  const REJECT_BUTTON = \"#reject-cookies\""
  },
  {
    "path": "test-e2e/specs/cypress/e2e/across-specs/save.cy.js",
    "chars": 826,
    "preview": "describe(\"Cookies buttons\", () => {\n  const ACCEPT_BUTTON = \"#accept-cookies\";\n  const REJECT_BUTTON = \"#reject-cookies\""
  },
  {
    "path": "test-e2e/specs/cypress/e2e/assertions-example.cy.js",
    "chars": 676,
    "preview": "describe(\"localStorage cookies-accepted item\", () => {\n  beforeEach(() => {\n    cy.restoreLocalStorage();\n    cy.visit(\""
  },
  {
    "path": "test-e2e/specs/cypress/e2e/cookies-example.cy.js",
    "chars": 1293,
    "preview": "describe(\"Accept cookies button\", () => {\n  const COOKIES_BUTTON = \"#accept-cookies\";\n  const LOCALSTORAGE_DISABLED_WARN"
  },
  {
    "path": "test-e2e/specs/cypress/e2e/cookies.cy.js",
    "chars": 8684,
    "preview": "describe(\"Cookies\", () => {\n  const SELECTORS = {\n    ACCEPT_BUTTON: \"#accept-cookies\",\n    REJECT_BUTTON: \"#reject-cook"
  },
  {
    "path": "test-e2e/specs/cypress/e2e/localstorage-disabled.cy.js",
    "chars": 642,
    "preview": "describe(\"when localStorage is disabled\", () => {\n  beforeEach(() => {\n    cy.disableLocalStorage({\n      withError: new"
  },
  {
    "path": "test-e2e/specs/cypress/e2e/named-across-specs/restore-after-clear.cy.js",
    "chars": 283,
    "preview": "describe(\"Cookies buttons\", () => {\n  const ACCEPT_BUTTON = \"#accept-cookies\";\n\n  it(\"accept should be visible after cle"
  },
  {
    "path": "test-e2e/specs/cypress/e2e/named-across-specs/restore.cy.js",
    "chars": 517,
    "preview": "describe(\"Cookies buttons\", () => {\n  const ACCEPT_BUTTON = \"#accept-cookies\";\n\n  it(\"accept should not be visible after"
  },
  {
    "path": "test-e2e/specs/cypress/e2e/named-across-specs/save.cy.js",
    "chars": 910,
    "preview": "describe(\"Cookies buttons\", () => {\n  const ACCEPT_BUTTON = \"#accept-cookies\";\n\n  before(() => {\n    cy.clearLocalStorag"
  },
  {
    "path": "test-e2e/specs/cypress/e2e/named-snapshots.cy.js",
    "chars": 1184,
    "preview": "describe(\"Accept cookies button using named snapshots\", () => {\n  const COOKIES_BUTTON = \"#accept-cookies\";\n\n  before(()"
  },
  {
    "path": "test-e2e/specs/cypress/e2e/no-across-specs/restore.cy.js",
    "chars": 407,
    "preview": "describe(\"Cookies buttons\", () => {\n  const ACCEPT_BUTTON = \"#accept-cookies\";\n  const REJECT_BUTTON = \"#reject-cookies\""
  },
  {
    "path": "test-e2e/specs/cypress/e2e/no-across-specs/save.cy.js",
    "chars": 826,
    "preview": "describe(\"Cookies buttons\", () => {\n  const ACCEPT_BUTTON = \"#accept-cookies\";\n  const REJECT_BUTTON = \"#reject-cookies\""
  },
  {
    "path": "tsconfig.json",
    "chars": 312,
    "preview": "{\n  \"compilerOptions\": {\n    \"target\": \"es6\",\n    \"module\": \"commonjs\",\n    \"outDir\": \"dist\",\n    \"moduleResolution\": \"n"
  }
]

About this extraction

This page contains the full source code of the javierbrea/cypress-localstorage-commands GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 137 files (139.9 KB), approximately 39.7k tokens, and a symbol index with 58 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!