@faststore/core 4.10.1-dev.3 → 4.10.1-dev.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-generate.log +3 -3
- package/.turbo/turbo-test.log +272 -233
- package/CHANGELOG.md +11 -0
- package/package.json +6 -6
- package/src/pages/api/graphql.ts +97 -57
- package/src/pages/pvt/account/403.tsx +5 -4
- package/src/sdk/account/useRefreshToken.ts +5 -6
- package/src/sdk/session/index.ts +42 -30
- package/src/utils/isLocalHost.ts +2 -16
- package/src/utils/shouldBypassRefreshToken.ts +63 -0
- package/test/pages/api/graphql.test.ts +175 -0
- package/test/pages/pvt/account/403.test.ts +67 -0
- package/test/sdk/account/useRefreshToken.browser.test.ts +69 -0
- package/test/sdk/session/validateSession.browser.test.ts +108 -5
- package/test/utils/shouldBypassRefreshToken.browser.test.ts +38 -0
- package/test/utils/shouldBypassRefreshToken.test.ts +98 -0
- package/test/utils/isLocalHost.browser.test.ts +0 -37
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
2
|
+
|
|
3
|
+
const mockExecute = vi.hoisted(() => vi.fn())
|
|
4
|
+
|
|
5
|
+
vi.mock('src/server', () => ({ execute: mockExecute }))
|
|
6
|
+
vi.mock('src/server/cms/global', () => ({
|
|
7
|
+
injectGlobalSections: vi.fn(() => ({ sections: [], settings: {} })),
|
|
8
|
+
}))
|
|
9
|
+
vi.mock('src/server/cms/fetchMyAccountPageContent', () => ({
|
|
10
|
+
fetchMyAccountPageContent: vi.fn(async () => ({ sections: [] })),
|
|
11
|
+
}))
|
|
12
|
+
vi.mock('src/components/cms/GlobalSections', () => ({
|
|
13
|
+
getGlobalSectionsData: vi.fn(() => [
|
|
14
|
+
Promise.resolve(null),
|
|
15
|
+
Promise.resolve(null),
|
|
16
|
+
Promise.resolve(null),
|
|
17
|
+
]),
|
|
18
|
+
}))
|
|
19
|
+
|
|
20
|
+
import storeConfig from 'discovery.config'
|
|
21
|
+
import { getServerSideProps } from 'src/pages/pvt/account/403'
|
|
22
|
+
|
|
23
|
+
function makeContext(host: string) {
|
|
24
|
+
return {
|
|
25
|
+
req: { headers: { host } },
|
|
26
|
+
query: {},
|
|
27
|
+
previewData: undefined,
|
|
28
|
+
locale: undefined,
|
|
29
|
+
} as any
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
describe('/pvt/account/403 getServerSideProps refresh-token bypass', () => {
|
|
33
|
+
const originalRefreshToken = storeConfig.experimental.refreshToken
|
|
34
|
+
|
|
35
|
+
beforeEach(() => {
|
|
36
|
+
storeConfig.experimental.refreshToken = true
|
|
37
|
+
vi.spyOn(console, 'error').mockImplementation(() => {})
|
|
38
|
+
mockExecute.mockResolvedValue({
|
|
39
|
+
data: null,
|
|
40
|
+
errors: [{ extensions: { status: 401 } }],
|
|
41
|
+
})
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
afterEach(() => {
|
|
45
|
+
storeConfig.experimental.refreshToken = originalRefreshToken
|
|
46
|
+
vi.restoreAllMocks()
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
it.each([
|
|
50
|
+
'localhost:3000',
|
|
51
|
+
'127.0.0.1:3000',
|
|
52
|
+
'brandless-abc123.preview.vtex.app',
|
|
53
|
+
])('does not ask for a token refresh on %s', async (host) => {
|
|
54
|
+
const result: any = await getServerSideProps(makeContext(host))
|
|
55
|
+
|
|
56
|
+
expect(result.props.needsRefreshToken).toBe(false)
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
it.each(['brandless.vtex.app', 'brandless.fast.store'])(
|
|
60
|
+
'asks for a token refresh on the production host %s',
|
|
61
|
+
async (host) => {
|
|
62
|
+
const result: any = await getServerSideProps(makeContext(host))
|
|
63
|
+
|
|
64
|
+
expect(result.props.needsRefreshToken).toBe(true)
|
|
65
|
+
}
|
|
66
|
+
)
|
|
67
|
+
})
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { renderHook, waitFor } from '@testing-library/react'
|
|
2
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
3
|
+
|
|
4
|
+
const mockRefreshTokenRequest = vi.hoisted(() => vi.fn())
|
|
5
|
+
const mockLogoutAndClearSession = vi.hoisted(() => vi.fn())
|
|
6
|
+
|
|
7
|
+
vi.mock('../../../src/sdk/account/refreshToken', () => ({
|
|
8
|
+
refreshTokenRequest: mockRefreshTokenRequest,
|
|
9
|
+
isRefreshTokenSuccessful: () => false,
|
|
10
|
+
}))
|
|
11
|
+
|
|
12
|
+
vi.mock('../../../src/sdk/session', () => ({
|
|
13
|
+
logoutAndClearSession: mockLogoutAndClearSession,
|
|
14
|
+
sessionStore: { read: () => null, readInitial: () => ({}) },
|
|
15
|
+
}))
|
|
16
|
+
|
|
17
|
+
import { useRefreshToken } from '../../../src/sdk/account/useRefreshToken'
|
|
18
|
+
|
|
19
|
+
const originalLocation = window.location
|
|
20
|
+
|
|
21
|
+
function stubHostname(hostname: string) {
|
|
22
|
+
// jsdom forbids assigning to `window.location` directly, so we redefine the
|
|
23
|
+
// descriptor with a minimal stub that exposes the hostname we want to test.
|
|
24
|
+
Object.defineProperty(window, 'location', {
|
|
25
|
+
configurable: true,
|
|
26
|
+
value: { ...originalLocation, hostname },
|
|
27
|
+
})
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
describe('useRefreshToken', () => {
|
|
31
|
+
beforeEach(() => {
|
|
32
|
+
mockRefreshTokenRequest.mockResolvedValue({ status: 'error' })
|
|
33
|
+
mockLogoutAndClearSession.mockResolvedValue(undefined)
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
afterEach(() => {
|
|
37
|
+
vi.clearAllMocks()
|
|
38
|
+
Object.defineProperty(window, 'location', {
|
|
39
|
+
configurable: true,
|
|
40
|
+
value: originalLocation,
|
|
41
|
+
})
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
it.each(['localhost', 'brandless-abc123.preview.vtex.app'])(
|
|
45
|
+
'shows the 403 view without refreshing or logging out on %s',
|
|
46
|
+
async (hostname) => {
|
|
47
|
+
stubHostname(hostname)
|
|
48
|
+
|
|
49
|
+
const { result } = renderHook(() => useRefreshToken(true))
|
|
50
|
+
|
|
51
|
+
await waitFor(() => expect(result.current.shouldShow403).toBe(true))
|
|
52
|
+
expect(mockRefreshTokenRequest).not.toHaveBeenCalled()
|
|
53
|
+
expect(mockLogoutAndClearSession).not.toHaveBeenCalled()
|
|
54
|
+
}
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
it.each(['brandless.vtex.app', 'brandless.fast.store'])(
|
|
58
|
+
'refreshes the token and logs out when it fails on %s',
|
|
59
|
+
async (hostname) => {
|
|
60
|
+
stubHostname(hostname)
|
|
61
|
+
|
|
62
|
+
const { result } = renderHook(() => useRefreshToken(true))
|
|
63
|
+
|
|
64
|
+
await waitFor(() => expect(result.current.shouldShow403).toBe(true))
|
|
65
|
+
expect(mockRefreshTokenRequest).toHaveBeenCalledTimes(1)
|
|
66
|
+
expect(mockLogoutAndClearSession).toHaveBeenCalledTimes(1)
|
|
67
|
+
}
|
|
68
|
+
)
|
|
69
|
+
})
|
|
@@ -1,12 +1,27 @@
|
|
|
1
1
|
import type { Session } from '@faststore/sdk'
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
afterEach,
|
|
4
|
+
beforeAll,
|
|
5
|
+
beforeEach,
|
|
6
|
+
describe,
|
|
7
|
+
expect,
|
|
8
|
+
it,
|
|
9
|
+
vi,
|
|
10
|
+
} from 'vitest'
|
|
3
11
|
|
|
4
12
|
const mockRequest = vi.hoisted(() => vi.fn())
|
|
13
|
+
const mockRefreshTokenRequest = vi.hoisted(() => vi.fn())
|
|
5
14
|
|
|
6
15
|
vi.mock('../../../src/sdk/graphql/request', () => ({
|
|
7
16
|
request: mockRequest,
|
|
8
17
|
}))
|
|
9
18
|
|
|
19
|
+
vi.mock('../../../src/sdk/account/refreshToken', () => ({
|
|
20
|
+
refreshTokenRequest: mockRefreshTokenRequest,
|
|
21
|
+
isRefreshTokenSuccessful: () => true,
|
|
22
|
+
}))
|
|
23
|
+
|
|
24
|
+
import storeConfig from '../../../discovery.config'
|
|
10
25
|
import { validateSession } from '../../../src/sdk/session'
|
|
11
26
|
|
|
12
27
|
const session: Session = {
|
|
@@ -25,12 +40,17 @@ const session: Session = {
|
|
|
25
40
|
refreshAfter: null,
|
|
26
41
|
}
|
|
27
42
|
|
|
43
|
+
// The store validates its initial session when the module loads. Let that
|
|
44
|
+
// call settle once, so no test depends on calls left by another one.
|
|
45
|
+
beforeAll(async () => {
|
|
46
|
+
mockRequest.mockResolvedValue({ validateSession: null })
|
|
47
|
+
await vi.waitFor(() => expect(mockRequest).toHaveBeenCalled())
|
|
48
|
+
})
|
|
49
|
+
|
|
28
50
|
describe('validateSession', () => {
|
|
29
|
-
beforeEach(
|
|
51
|
+
beforeEach(() => {
|
|
52
|
+
mockRequest.mockReset()
|
|
30
53
|
mockRequest.mockResolvedValue({ validateSession: null })
|
|
31
|
-
// The store validates its initial session on load; let it settle first
|
|
32
|
-
await vi.waitFor(() => expect(mockRequest).toHaveBeenCalled())
|
|
33
|
-
mockRequest.mockClear()
|
|
34
54
|
})
|
|
35
55
|
|
|
36
56
|
it('does not send the UI state persisted with the session', async () => {
|
|
@@ -45,3 +65,86 @@ describe('validateSession', () => {
|
|
|
45
65
|
expect(mockRequest.mock.calls[0][1].session).toStrictEqual(session)
|
|
46
66
|
})
|
|
47
67
|
})
|
|
68
|
+
|
|
69
|
+
describe('validateSession refresh-token bypass', () => {
|
|
70
|
+
const originalLocation = window.location
|
|
71
|
+
const originalRefreshToken = storeConfig.experimental.refreshToken
|
|
72
|
+
|
|
73
|
+
// An already expired `refreshAfter` (in seconds) triggers the refresh path.
|
|
74
|
+
const expiredSession: Session = { ...session, refreshAfter: '1' }
|
|
75
|
+
|
|
76
|
+
function stubHostname(hostname: string) {
|
|
77
|
+
// jsdom forbids assigning to `window.location` directly, so we redefine the
|
|
78
|
+
// descriptor with a minimal stub that exposes the hostname we want to test.
|
|
79
|
+
Object.defineProperty(window, 'location', {
|
|
80
|
+
configurable: true,
|
|
81
|
+
value: { ...originalLocation, hostname },
|
|
82
|
+
})
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
beforeEach(() => {
|
|
86
|
+
mockRequest.mockReset()
|
|
87
|
+
mockRequest.mockResolvedValue({ validateSession: null })
|
|
88
|
+
mockRefreshTokenRequest.mockReset()
|
|
89
|
+
mockRefreshTokenRequest.mockResolvedValue({
|
|
90
|
+
status: 'success',
|
|
91
|
+
refreshAfter: new Date(Date.now() + 60_000).toISOString(),
|
|
92
|
+
})
|
|
93
|
+
storeConfig.experimental.refreshToken = true
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
afterEach(() => {
|
|
97
|
+
storeConfig.experimental.refreshToken = originalRefreshToken
|
|
98
|
+
Object.defineProperty(window, 'location', {
|
|
99
|
+
configurable: true,
|
|
100
|
+
value: originalLocation,
|
|
101
|
+
})
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
it.each(['localhost', 'brandless-abc123.preview.vtex.app'])(
|
|
105
|
+
'skips the refresh when refreshAfter is expired on %s',
|
|
106
|
+
async (hostname) => {
|
|
107
|
+
stubHostname(hostname)
|
|
108
|
+
|
|
109
|
+
await validateSession(expiredSession)
|
|
110
|
+
|
|
111
|
+
expect(mockRefreshTokenRequest).not.toHaveBeenCalled()
|
|
112
|
+
expect(mockRequest).toHaveBeenCalledTimes(1)
|
|
113
|
+
}
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
it.each(['localhost', 'brandless-abc123.preview.vtex.app'])(
|
|
117
|
+
'skips the refresh when ValidateSession answers 401 on %s',
|
|
118
|
+
async (hostname) => {
|
|
119
|
+
stubHostname(hostname)
|
|
120
|
+
mockRequest.mockRejectedValueOnce({ status: 401 })
|
|
121
|
+
|
|
122
|
+
await validateSession(session)
|
|
123
|
+
|
|
124
|
+
expect(mockRefreshTokenRequest).not.toHaveBeenCalled()
|
|
125
|
+
}
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
it.each(['brandless.vtex.app', 'brandless.fast.store'])(
|
|
129
|
+
'refreshes the token when refreshAfter is expired on %s',
|
|
130
|
+
async (hostname) => {
|
|
131
|
+
stubHostname(hostname)
|
|
132
|
+
|
|
133
|
+
await validateSession(expiredSession)
|
|
134
|
+
|
|
135
|
+
expect(mockRefreshTokenRequest).toHaveBeenCalledTimes(1)
|
|
136
|
+
}
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
it.each(['brandless.vtex.app', 'brandless.fast.store'])(
|
|
140
|
+
'refreshes the token when ValidateSession answers 401 on %s',
|
|
141
|
+
async (hostname) => {
|
|
142
|
+
stubHostname(hostname)
|
|
143
|
+
mockRequest.mockRejectedValueOnce({ status: 401 })
|
|
144
|
+
|
|
145
|
+
await validateSession(session)
|
|
146
|
+
|
|
147
|
+
expect(mockRefreshTokenRequest).toHaveBeenCalledTimes(1)
|
|
148
|
+
}
|
|
149
|
+
)
|
|
150
|
+
})
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it } from 'vitest'
|
|
2
|
+
import { shouldBypassRefreshTokenBrowser } from '../../src/utils/shouldBypassRefreshToken'
|
|
3
|
+
|
|
4
|
+
const originalLocation = window.location
|
|
5
|
+
|
|
6
|
+
function stubHostname(hostname: string) {
|
|
7
|
+
// jsdom forbids assigning to `window.location` directly, so we redefine the
|
|
8
|
+
// descriptor with a minimal stub that exposes the hostname we want to test.
|
|
9
|
+
Object.defineProperty(window, 'location', {
|
|
10
|
+
configurable: true,
|
|
11
|
+
value: { ...originalLocation, hostname },
|
|
12
|
+
})
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
describe('shouldBypassRefreshTokenBrowser', () => {
|
|
16
|
+
afterEach(() => {
|
|
17
|
+
Object.defineProperty(window, 'location', {
|
|
18
|
+
configurable: true,
|
|
19
|
+
value: originalLocation,
|
|
20
|
+
})
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
it.each(['localhost', '127.0.0.1', 'brandless-abc123.preview.vtex.app'])(
|
|
24
|
+
'returns true when window.location.hostname is "%s"',
|
|
25
|
+
(hostname) => {
|
|
26
|
+
stubHostname(hostname)
|
|
27
|
+
expect(shouldBypassRefreshTokenBrowser()).toBe(true)
|
|
28
|
+
}
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
it.each(['brandless.vtex.app', 'brandless.fast.store'])(
|
|
32
|
+
'returns false for the production hostname "%s"',
|
|
33
|
+
(hostname) => {
|
|
34
|
+
stubHostname(hostname)
|
|
35
|
+
expect(shouldBypassRefreshTokenBrowser()).toBe(false)
|
|
36
|
+
}
|
|
37
|
+
)
|
|
38
|
+
})
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import {
|
|
3
|
+
shouldBypassRefreshToken,
|
|
4
|
+
shouldBypassRefreshTokenBrowser,
|
|
5
|
+
shouldBypassRefreshTokenForRequest,
|
|
6
|
+
} from '../../src/utils/shouldBypassRefreshToken'
|
|
7
|
+
|
|
8
|
+
describe('shouldBypassRefreshToken', () => {
|
|
9
|
+
it.each(['localhost', '127.0.0.1'])('returns true for "%s"', (hostname) => {
|
|
10
|
+
expect(shouldBypassRefreshToken(hostname)).toBe(true)
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
it('returns true for a WebOps preview host', () => {
|
|
14
|
+
expect(shouldBypassRefreshToken('brandless-abc123.preview.vtex.app')).toBe(
|
|
15
|
+
true
|
|
16
|
+
)
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
it('is case-insensitive for preview hosts', () => {
|
|
20
|
+
expect(shouldBypassRefreshToken('Brandless-ABC123.Preview.VTEX.app')).toBe(
|
|
21
|
+
true
|
|
22
|
+
)
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
it('ignores the trailing dot of a fully qualified preview host', () => {
|
|
26
|
+
expect(shouldBypassRefreshToken('brandless-abc123.preview.vtex.app.')).toBe(
|
|
27
|
+
true
|
|
28
|
+
)
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
it('returns false for the production "{account}.vtex.app" domain', () => {
|
|
32
|
+
// `{account}.vtex.app` is a production default domain, not a preview.
|
|
33
|
+
expect(shouldBypassRefreshToken('brandless.vtex.app')).toBe(false)
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
it('returns false for a custom store domain', () => {
|
|
37
|
+
expect(shouldBypassRefreshToken('brandless.fast.store')).toBe(false)
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
it('returns false for hosts that only contain the preview suffix', () => {
|
|
41
|
+
expect(shouldBypassRefreshToken('preview.vtex.app')).toBe(false)
|
|
42
|
+
expect(shouldBypassRefreshToken('x.preview.vtex.app.evil.com')).toBe(false)
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
it('returns false for nullish or empty input', () => {
|
|
46
|
+
expect(shouldBypassRefreshToken(null)).toBe(false)
|
|
47
|
+
expect(shouldBypassRefreshToken(undefined)).toBe(false)
|
|
48
|
+
expect(shouldBypassRefreshToken('')).toBe(false)
|
|
49
|
+
})
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
describe('shouldBypassRefreshTokenForRequest', () => {
|
|
53
|
+
it('returns true when the Host header is a local or preview host', () => {
|
|
54
|
+
expect(shouldBypassRefreshTokenForRequest({ host: 'localhost:3000' })).toBe(
|
|
55
|
+
true
|
|
56
|
+
)
|
|
57
|
+
expect(
|
|
58
|
+
shouldBypassRefreshTokenForRequest({
|
|
59
|
+
host: 'brandless-abc123.preview.vtex.app',
|
|
60
|
+
})
|
|
61
|
+
).toBe(true)
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
it('returns true when the preview host arrives in x-forwarded-host', () => {
|
|
65
|
+
// Behind the preview ingress, Host is an internal name.
|
|
66
|
+
expect(
|
|
67
|
+
shouldBypassRefreshTokenForRequest({
|
|
68
|
+
host: 'faststore-internal:3000',
|
|
69
|
+
'x-forwarded-host': 'brandless-abc123.preview.vtex.app',
|
|
70
|
+
})
|
|
71
|
+
).toBe(true)
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
it('ignores a multi-value x-forwarded-host', () => {
|
|
75
|
+
expect(
|
|
76
|
+
shouldBypassRefreshTokenForRequest({
|
|
77
|
+
host: 'brandless.fast.store',
|
|
78
|
+
'x-forwarded-host': 'brandless-abc123.preview.vtex.app, proxy',
|
|
79
|
+
})
|
|
80
|
+
).toBe(false)
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
it('returns false on production hosts', () => {
|
|
84
|
+
expect(
|
|
85
|
+
shouldBypassRefreshTokenForRequest({
|
|
86
|
+
host: 'brandless.fast.store',
|
|
87
|
+
'x-forwarded-host': 'brandless.fast.store',
|
|
88
|
+
})
|
|
89
|
+
).toBe(false)
|
|
90
|
+
expect(shouldBypassRefreshTokenForRequest({})).toBe(false)
|
|
91
|
+
})
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
describe('shouldBypassRefreshTokenBrowser', () => {
|
|
95
|
+
it('returns false when window is not available (SSR/Node)', () => {
|
|
96
|
+
expect(shouldBypassRefreshTokenBrowser()).toBe(false)
|
|
97
|
+
})
|
|
98
|
+
})
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { afterEach, describe, expect, it } from 'vitest'
|
|
2
|
-
import { isLocalHostBrowser } from '../../src/utils/isLocalHost'
|
|
3
|
-
|
|
4
|
-
const originalLocation = window.location
|
|
5
|
-
|
|
6
|
-
function stubHostname(hostname: string) {
|
|
7
|
-
// jsdom forbids assigning to `window.location` directly, so we redefine the
|
|
8
|
-
// descriptor with a minimal stub that exposes the hostname we want to test.
|
|
9
|
-
Object.defineProperty(window, 'location', {
|
|
10
|
-
configurable: true,
|
|
11
|
-
value: { ...originalLocation, hostname },
|
|
12
|
-
})
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
describe('isLocalHostBrowser', () => {
|
|
16
|
-
afterEach(() => {
|
|
17
|
-
Object.defineProperty(window, 'location', {
|
|
18
|
-
configurable: true,
|
|
19
|
-
value: originalLocation,
|
|
20
|
-
})
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
it('returns true when window.location.hostname is "localhost"', () => {
|
|
24
|
-
stubHostname('localhost')
|
|
25
|
-
expect(isLocalHostBrowser()).toBe(true)
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
it('returns true when window.location.hostname is "127.0.0.1"', () => {
|
|
29
|
-
stubHostname('127.0.0.1')
|
|
30
|
-
expect(isLocalHostBrowser()).toBe(true)
|
|
31
|
-
})
|
|
32
|
-
|
|
33
|
-
it('returns false for a production hostname', () => {
|
|
34
|
-
stubHostname('brandless.fast.store')
|
|
35
|
-
expect(isLocalHostBrowser()).toBe(false)
|
|
36
|
-
})
|
|
37
|
-
})
|