Skip to content

Commit a3786ce

Browse files
committed
feat(to-have-local-storage-item): add expect browser local Storage utilization function
1 parent 3841052 commit a3786ce

File tree

3 files changed

+202
-0
lines changed

3 files changed

+202
-0
lines changed

src/matchers.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export * from './matchers/browser/toHaveClipboardText.js'
2+
export * from './matchers/browser/toHaveLocalStorageItem.js'
23
export * from './matchers/browser/toHaveTitle.js'
34
export * from './matchers/browser/toHaveUrl.js'
45
export * from './matchers/element/toBeClickable.js'
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { waitUntil, enhanceError, compareText } from '../../utils.js'
2+
import { DEFAULT_OPTIONS } from '../../constants.js'
3+
4+
export async function toHaveLocalStorageItem(
5+
browser: WebdriverIO.Browser,
6+
key: string,
7+
expectedValue?: string | RegExp | ExpectWebdriverIO.PartialMatcher,
8+
options: ExpectWebdriverIO.StringOptions = DEFAULT_OPTIONS
9+
) {
10+
const isNot = this.isNot
11+
const { expectation = 'localStorage item', verb = 'have' } = this
12+
13+
await options.beforeAssertion?.({
14+
matcherName: 'toHaveLocalStorageItem',
15+
expectedValue: expectedValue ? [key, expectedValue] : key,
16+
options,
17+
})
18+
let actual
19+
const pass = await waitUntil(async () => {
20+
actual = await browser.execute((storageKey) => {
21+
return localStorage.getItem(storageKey)
22+
}, key)
23+
// if no expected value is provided, we just check if the item exists
24+
if (expectedValue === undefined) {
25+
return actual !== null
26+
}
27+
// no localStorage item found
28+
if (actual === null) {
29+
return false
30+
}
31+
return compareText(actual, expectedValue, options).result
32+
}, isNot, options)
33+
const message = enhanceError(
34+
'browser',
35+
expectedValue !== undefined ? expectedValue : `localStorage item "${key}"`,
36+
actual,
37+
this,
38+
verb,
39+
expectation,
40+
key,
41+
options
42+
)
43+
const result: ExpectWebdriverIO.AssertionResult = {
44+
pass,
45+
message: () => message
46+
}
47+
await options.afterAssertion?.({
48+
matcherName: 'toHaveLocalStorageItem',
49+
expectedValue: expectedValue ? [key, expectedValue] : key,
50+
options,
51+
result
52+
})
53+
return result
54+
}
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
import { vi, expect, describe, it, beforeEach } from 'vitest'
2+
import { browser } from '@wdio/globals'
3+
import { toHaveLocalStorageItem } from '../../../src/matchers/browser/toHaveLocalStorageItem.js'
4+
5+
vi.mock('@wdio/globals')
6+
7+
const beforeAssertion = vi.fn()
8+
const afterAssertion = vi.fn()
9+
10+
describe('toHaveLocalStorageItem', () => {
11+
beforeEach(() => {
12+
vi.clearAllMocks()
13+
})
14+
15+
it('passes when localStorage item exists with correct value', async () => {
16+
browser.execute = vi.fn().mockResolvedValue('someLocalStorageValue')
17+
18+
const result = await toHaveLocalStorageItem.call(
19+
{}, // this context
20+
browser,
21+
'someLocalStorageKey',
22+
'someLocalStorageValue',
23+
{ ignoreCase: true, beforeAssertion, afterAssertion }
24+
)
25+
26+
expect(result.pass).toBe(true)
27+
28+
// Check that browser.execute was called with correct arguments
29+
expect(browser.execute).toHaveBeenCalledWith(
30+
expect.any(Function),
31+
'someLocalStorageKey'
32+
)
33+
34+
expect(beforeAssertion).toHaveBeenCalledWith({
35+
matcherName: 'toHaveLocalStorageItem',
36+
expectedValue: ['someLocalStorageKey', 'someLocalStorageValue'],
37+
options: { ignoreCase: true, beforeAssertion, afterAssertion }
38+
})
39+
40+
expect(afterAssertion).toHaveBeenCalledWith({
41+
matcherName: 'toHaveLocalStorageItem',
42+
expectedValue: ['someLocalStorageKey', 'someLocalStorageValue'],
43+
options: { ignoreCase: true, beforeAssertion, afterAssertion },
44+
result
45+
})
46+
})
47+
48+
it('fails when localStorage item has different value', async () => {
49+
browser.execute = vi.fn().mockResolvedValue('actualValue')
50+
51+
const result = await toHaveLocalStorageItem.call(
52+
{},
53+
browser,
54+
'someKey',
55+
'expectedValue'
56+
)
57+
58+
expect(result.pass).toBe(false)
59+
})
60+
61+
it('fails when localStorage item does not exist', async () => {
62+
// Mock browser.execute to return null (item doesn't exist)
63+
browser.execute = vi.fn().mockResolvedValue(null)
64+
65+
const result = await toHaveLocalStorageItem.call(
66+
{},
67+
browser,
68+
'nonExistentKey',
69+
'someValue'
70+
)
71+
72+
expect(result.pass).toBe(false)
73+
expect(browser.execute).toHaveBeenCalledWith(
74+
expect.any(Function),
75+
'nonExistentKey'
76+
)
77+
})
78+
79+
it('passes when only checking key existence', async () => {
80+
// Mock browser.execute to return any non-null value
81+
browser.execute = vi.fn().mockResolvedValue('anyValue')
82+
83+
const result = await toHaveLocalStorageItem.call(
84+
{},
85+
browser,
86+
'existingKey'
87+
// no expectedValue parameter
88+
)
89+
90+
expect(result.pass).toBe(true)
91+
})
92+
93+
it('ignores case when ignoreCase is true', async () => {
94+
browser.execute = vi.fn().mockResolvedValue('UPPERCASE')
95+
96+
const result = await toHaveLocalStorageItem.call(
97+
{},
98+
browser,
99+
'key',
100+
'uppercase',
101+
{ ignoreCase: true }
102+
)
103+
104+
expect(result.pass).toBe(true)
105+
})
106+
107+
it('trims whitespace when trim is true', async () => {
108+
browser.execute = vi.fn().mockResolvedValue(' value ')
109+
110+
const result = await toHaveLocalStorageItem.call(
111+
{},
112+
browser,
113+
'key',
114+
'value',
115+
{ trim: true }
116+
)
117+
118+
expect(result.pass).toBe(true)
119+
})
120+
121+
it('checks containing when containing is true', async () => {
122+
browser.execute = vi.fn().mockResolvedValue('this is a long value')
123+
124+
const result = await toHaveLocalStorageItem.call(
125+
{},
126+
browser,
127+
'key',
128+
'long',
129+
{ containing: true }
130+
)
131+
132+
expect(result.pass).toBe(true)
133+
})
134+
135+
it('passes when localStorage value matches regex', async () => {
136+
browser.execute = vi.fn().mockResolvedValue('user_123')
137+
138+
const result = await toHaveLocalStorageItem.call(
139+
{},
140+
browser,
141+
'userId',
142+
/^user_\d+$/
143+
)
144+
145+
expect(result.pass).toBe(true)
146+
})
147+
})

0 commit comments

Comments
 (0)