Skip to content

Commit 98f64dc

Browse files
authored
Merge pull request #205 from javierbrea/release
Release v1.3.0
2 parents 54948ff + 19145c2 commit 98f64dc

32 files changed

+744
-115
lines changed

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,17 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1111
### Removed
1212
### BREAKING CHANGES
1313

14+
## [1.3.0] - 2020-12-07
15+
16+
### Added
17+
- feat(#191): Add disableLocalStorage command (Thanks to @Uninen for his contribution).
18+
19+
### Changed
20+
- chore(deps): Update some devDependencies
21+
22+
### Fixed
23+
- style(lint): Lint also files in root folder. Fix jest.config style
24+
1425
## [1.2.5] - 2020-12-05
1526

1627
### Changed

README.md

Lines changed: 102 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,16 @@
66

77
# Cypress localStorage commands
88

9-
Extends Cypress' cy commands with localStorage methods. Allows preserving localStorage between tests.
9+
Extends Cypress' cy commands with localStorage methods. Allows preserving localStorage between tests and disabling localStorage.
1010

11-
## The problem
11+
## The problems
1212

13-
You want to preserve localStorage between Cypress tests.
13+
* You want to preserve localStorage between Cypress tests.
14+
* You want to disable localStorage to check error handling.
1415

1516
## This solution
1617

17-
This solution allows you to use all browser localStorage methods through Cypress commands, and preserve it between tests.
18+
This solution allows you to use all browser localStorage methods through Cypress commands, and preserve it between tests. It also allows to simulate that localStorage is disabled in the browser.
1819

1920
## Installation
2021

@@ -38,45 +39,47 @@ You can now use all next commands:
3839

3940
### Commands
4041

41-
Save current localStorage values into an internal "snapshot":
42+
##### `cy.saveLocalStorage()`
4243

43-
```js
44-
cy.saveLocalStorage();
45-
```
44+
Saves current localStorage values into an internal "snapshot".
4645

47-
Restore localStorage to previously "snapshot" saved values:
46+
##### `cy.restoreLocalStorage()`
4847

49-
```js
50-
cy.restoreLocalStorage();
51-
```
48+
Restores localStorage to previously "snapshot" saved values.
5249

53-
Clear localStorage "snapshot" values:
50+
##### `cy.clearLocalStorageSnapshot()`
5451

55-
```js
56-
cy.clearLocalStorageSnapshot();
57-
```
52+
Clears localStorage "snapshot" values, so previously saved values are cleaned.
5853

59-
Get localStorage item. Equivalent to `localStorage.getItem` in browser:
54+
##### `cy.getLocalStorage(item)`
6055

61-
```js
62-
cy.getLocalStorage("item");
63-
```
56+
Gets localStorage item. Equivalent to `localStorage.getItem` in browser.
6457

65-
Set localStorage item. Equivalent to `localStorage.setItem` in browser:
58+
* `item` _(String)_: Item to get from `localStorage`.
6659

67-
```js
68-
cy.setLocalStorage("item", "value");
69-
```
60+
##### `cy.setLocalStorage(item, value)`
7061

71-
Remove localStorage item. Equivalent to `localStorage.removeItem` in browser:
62+
Sets localStorage item. Equivalent to `localStorage.setItem` in browser.
7263

73-
```js
74-
cy.removeLocalStorage("item");
75-
```
64+
* `item` _(String)_: Item to set value.
65+
* `value` _(String)_: Value to be set.
66+
67+
##### `cy.removeLocalStorage(item)`
68+
69+
Removes localStorage item. Equivalent to `localStorage.removeItem` in browser.
70+
71+
* `item` _(String)_: Item to be removed.
72+
73+
##### `cy.disableLocalStorage(options)`
74+
75+
Disables localStorage. It produces localStorage methods to throw errors.
76+
77+
* `options` _(Object)_: Options to use when disabling `localStorage`.
78+
* `withError` _(Error)_: If provided, invocations to `localStorage` methods will throw this error.
7679

7780
### Preserving local storage between tests
7881

79-
Use `saveLocalStorage` to save a snapshot of current `localStorage` at the end of one test, and use the `restoreLocalStorage` command to restore it at the beginning of another one. _The usage of `beforeEach` and `afterEach` is recommended for this purpose._
82+
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._
8083

8184
### Examples
8285

@@ -116,7 +119,7 @@ describe("Accept cookies button", () => {
116119
});
117120
```
118121

119-
> Note the usage of `beforeEach` and `afterEach` for preserving `localStorage` between all tests. Also `clearLocalStorageSnapshot` is used in the `before` statement to avoid possible conflicts with other test files preserving localStorage.
122+
> 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 test files preserving localStorage.
120123
121124
#### localStorage assertions
122125

@@ -150,6 +153,75 @@ describe("localStorage cookies-accepted item", () => {
150153
});
151154
```
152155

156+
### Disabling localStorage
157+
158+
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.
159+
160+
Note that:
161+
162+
* Only pages loaded after calling this command will have `localStorage` disabled, so always use `cy.reload` or `cy.visit` after executing it.
163+
* 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.
164+
* 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"_
165+
166+
### Examples
167+
168+
#### Disabling localStorage in a single test
169+
170+
Based on previous "Accept cookies button" example, next tests could be added:
171+
172+
```js
173+
//...
174+
const LOCALSTORAGE_DISABLED_WARNING = "#localstorage-disabled-warning";
175+
const LOCALSTORAGE_ERROR = "#localstorage-error";
176+
177+
//... should not be visible after clicked
178+
179+
it("should still be visible when reloading if localStorage is disabled", () => {
180+
cy.disableLocalStorage();
181+
cy.reload();
182+
cy.get(COOKIES_BUTTON).should("be.visible");
183+
});
184+
185+
it("should display warning if localStorage is disabled", () => {
186+
cy.disableLocalStorage();
187+
cy.reload();
188+
cy.get(LOCALSTORAGE_DISABLED_WARNING).should("be.visible");
189+
});
190+
191+
it("should display localStorage error message", () => {
192+
cy.disableLocalStorage();
193+
cy.reload();
194+
cy.get(LOCALSTORAGE_ERROR).should("have.text", "Error");
195+
});
196+
197+
// ...should not be visible after reloading
198+
```
199+
200+
#### Disabling localStorage in multiple tests
201+
202+
```js
203+
describe("when localStorage is disabled", () => {
204+
beforeEach(() => {
205+
cy.disableLocalStorage({
206+
withError: new Error("Disabled by cypress-localstorage-commands"),
207+
});
208+
cy.visit("/");
209+
});
210+
211+
it("should display localStorage warning", () => {
212+
cy.get("#localstorage-disabled-warning").should("be.visible");
213+
});
214+
215+
it("should display localStorage error message", () => {
216+
cy.get("#localstorage-error").should("have.text", "Disabled by cypress-localstorage-commands");
217+
});
218+
219+
it("should display accept-cookies button disabled", () => {
220+
cy.get("#accept-cookies").should("be.disabled");
221+
});
222+
});
223+
```
224+
153225
## Usage with TypeScript
154226

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

index.d.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,5 +41,14 @@ declare namespace Cypress {
4141
* @example cy.removeLocalStorage("cookies-accepted")
4242
*/
4343
removeLocalStorage(itemKeyName: string): Chainable<undefined>
44+
45+
/**
46+
* Command to disable localStorage
47+
* @param {object} options - Options for disabling localStorage
48+
* @example cy.disableLocalStorage()
49+
*/
50+
disableLocalStorage(options?: {
51+
withError: Error
52+
}): Chainable<undefined>
4453
}
4554
}

index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
/* global Cypress, localStorage */
1+
/* global Cypress, cy, localStorage */
22

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

5-
register(Cypress, localStorage);
5+
register(Cypress, cy, localStorage);

jest.config.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,13 @@ module.exports = {
2020
branches: 100,
2121
functions: 100,
2222
lines: 100,
23-
statements: 100
24-
}
23+
statements: 100,
24+
},
2525
},
2626

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

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

package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "cypress-localstorage-commands",
3-
"version": "1.2.5",
3+
"version": "1.3.0",
44
"description": "Extends Cypress' cy commands with localStorage methods. Allows preserving localStorage between tests",
55
"keywords": [
66
"cypress",
@@ -23,7 +23,7 @@
2323
"main": "index.js",
2424
"scripts": {
2525
"lint:typescript": "cd test-e2e/typescript && npm run copy:library && npm run lint",
26-
"lint:javascript": "eslint src test test-e2e/react-app/src test-e2e/react-app/cypress",
26+
"lint:javascript": "eslint src test test-e2e/react-app/src test-e2e/react-app/cypress test-e2e/react-app/*.js *.js",
2727
"lint:all": "npm run lint:javascript && npm run lint:typescript",
2828
"lint": "npm run test:e2e:typescript:install && npm run lint:all",
2929
"lint:local": "npm run lint:all",
@@ -48,7 +48,7 @@
4848
"babel-eslint": "10.1.0",
4949
"eslint": "7.14.0",
5050
"eslint-config-prettier": "6.15.0",
51-
"eslint-plugin-prettier": "3.1.4",
51+
"eslint-plugin-prettier": "3.2.0",
5252
"eslint-plugin-react": "7.21.5",
5353
"husky": "4.3.0",
5454
"jest": "26.6.3",
@@ -57,8 +57,10 @@
5757
"sinon": "9.2.1"
5858
},
5959
"lint-staged": {
60+
"*.js": "eslint",
6061
"src/**/*.js": "eslint",
6162
"test/**/*.js": "eslint",
63+
"test-e2e/react-app/*.js": "eslint",
6264
"test-e2e/react-app/src/**/*.js": "eslint",
6365
"test-e2e/react-app/cypress/**/*.js": "eslint",
6466
"test-e2e/typescript/**/*.js": "npm run lint:typescript",

sonar-project.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
sonar.organization=javierbrea
22
sonar.projectKey=cypress-localstorage-commands
3-
sonar.projectVersion=1.2.5
3+
sonar.projectVersion=1.3.0
44

55
sonar.javascript.file.suffixes=.js
66
sonar.sourceEncoding=UTF-8

src/LocalStorage.js

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,15 @@
1+
const LOCAL_STORAGE_METHODS = ["setItem", "getItem", "removeItem", "clear"];
2+
3+
function logDisabled(method) {
4+
return function () {
5+
this._cy.log(`localStorage.${method} is disabled`);
6+
};
7+
}
8+
9+
function logDisabledMethodName(localStorageMethod) {
10+
return `_log${localStorageMethod}Disabled`;
11+
}
12+
113
class LocalStorage {
214
static get cypressCommands() {
315
return [
@@ -7,11 +19,16 @@ class LocalStorage {
719
"setLocalStorage",
820
"getLocalStorage",
921
"removeLocalStorage",
22+
"disableLocalStorage",
1023
];
1124
}
1225

13-
constructor(localStorage) {
26+
constructor(localStorage, cy) {
27+
this._cy = cy;
1428
this._localStorage = localStorage;
29+
LOCAL_STORAGE_METHODS.forEach((localStorageMethod) => {
30+
this[logDisabledMethodName(localStorageMethod)] = logDisabled(localStorageMethod).bind(this);
31+
});
1532
this.clearLocalStorageSnapshot();
1633
}
1734

@@ -20,10 +37,12 @@ class LocalStorage {
2037
}
2138

2239
saveLocalStorage() {
23-
this.clearLocalStorageSnapshot();
24-
Object.keys(this._localStorage).forEach((key) => {
25-
this._snapshot[key] = this._localStorage.getItem(key);
26-
});
40+
if (!this._localStorage.getItem.wrappedMethod) {
41+
this.clearLocalStorageSnapshot();
42+
Object.keys(this._localStorage).forEach((key) => {
43+
this._snapshot[key] = this._localStorage.getItem(key);
44+
});
45+
}
2746
}
2847

2948
restoreLocalStorage() {
@@ -44,6 +63,23 @@ class LocalStorage {
4463
removeLocalStorage(key) {
4564
return this._localStorage.removeItem(key);
4665
}
66+
67+
disableLocalStorage(options = {}) {
68+
this._cy.on("window:before:load", (win) => {
69+
if (
70+
win.localStorage &&
71+
!win.localStorage[LOCAL_STORAGE_METHODS[0]].wrappedMethod &&
72+
!this._localStorage[LOCAL_STORAGE_METHODS[0]].wrappedMethod
73+
) {
74+
LOCAL_STORAGE_METHODS.forEach((localStorageMethod) => {
75+
this._cy
76+
.stub(this._localStorage, localStorageMethod)
77+
.callsFake(this[logDisabledMethodName(localStorageMethod)]);
78+
this._cy.stub(win.localStorage, localStorageMethod).throws(options.withError);
79+
});
80+
}
81+
});
82+
}
4783
}
4884

4985
module.exports = LocalStorage;

src/register.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
const LocalStorage = require("./LocalStorage");
22

3-
const register = (Cypress, localStorage) => {
4-
const localStorageCommands = new LocalStorage(localStorage);
3+
const register = (Cypress, cy, localStorage) => {
4+
const localStorageCommands = new LocalStorage(localStorage, cy);
5+
6+
// Register commands
57
LocalStorage.cypressCommands.forEach((commandName) => {
68
Cypress.Commands.add(
79
commandName,

0 commit comments

Comments
 (0)