Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions config/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,8 @@ module.exports = {
testMatch: ["**/*.test.js"],
coverageDirectory: "../coverage",
testEnvironment: "jsdom",
watchPlugins: [
"jest-watch-typeahead/filename",
"jest-watch-typeahead/testname",
],
}
1,654 changes: 1,061 additions & 593 deletions package-lock.json

Large diffs are not rendered by default.

7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@
"@typescript-eslint/eslint-plugin": "^4.33.0",
"@typescript-eslint/parser": "^4.33.0",
"autoprefixer": "^10.3.7",
"babel-jest": "^27.2.4",
"babel-jest": "^27.3.0",
"babel-plugin-jsx-pragmatic": "^1.0.2",
"babel-preset-preact": "^2.0.0",
"conventional-changelog-conventionalcommits": "4.6.1",
Expand All @@ -102,12 +102,13 @@
"eslint-config-prettier": "^8.3.0",
"eslint-config-standard-with-typescript": "^21.0.1",
"eslint-plugin-import": "^2.24.2",
"eslint-plugin-jest": "^24.5.2",
"eslint-plugin-jest": "^25.2.2",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^5.1.0",
"fs-extra": "^10.0.0",
"husky": "^7.0.2",
"jest": "^27.2.4",
"jest": "^27.3.0",
"jest-watch-typeahead": "^1.0.0",
"msw": "^0.35.0",
"next": "v11.1.3-canary.0",
"postcss-cli": "^9.0.1",
Expand Down
18 changes: 10 additions & 8 deletions src/client/__tests__/helpers/mocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,26 +65,28 @@ export const mockSignOutResponse = {
}

export const server = setupServer(
rest.post("/api/auth/signout", (req, res, ctx) =>
rest.post("http://localhost/api/auth/signout", (req, res, ctx) =>
res(ctx.status(200), ctx.json(mockSignOutResponse))
),
rest.get("/api/auth/session", (req, res, ctx) =>
rest.get("http://localhost/api/auth/session", (req, res, ctx) =>
res(ctx.status(200), ctx.json(mockSession))
),
rest.get("/api/auth/csrf", (req, res, ctx) =>
rest.get("http://localhost/api/auth/csrf", (req, res, ctx) =>
res(ctx.status(200), ctx.json(mockCSRFToken))
),
rest.get("/api/auth/providers", (req, res, ctx) =>
rest.get("http://localhost/api/auth/providers", (req, res, ctx) =>
res(ctx.status(200), ctx.json(mockProviders))
),
rest.post("/api/auth/signin/github", (req, res, ctx) =>
rest.post("http://localhost/api/auth/signin/github", (req, res, ctx) =>
res(ctx.status(200), ctx.json(mockGithubResponse))
),
rest.post("/api/auth/callback/credentials", (req, res, ctx) =>
rest.post("http://localhost/api/auth/callback/credentials", (req, res, ctx) =>
res(ctx.status(200), ctx.json(mockCredentialsResponse))
),
rest.post("/api/auth/signin/email", (req, res, ctx) =>
rest.post("http://localhost/api/auth/signin/email", (req, res, ctx) =>
res(ctx.status(200), ctx.json(mockEmailResponse))
),
rest.post("/api/auth/_log", (req, res, ctx) => res(ctx.status(200)))
rest.post("http://localhost/api/auth/_log", (req, res, ctx) =>
res(ctx.status(200))
)
)
61 changes: 31 additions & 30 deletions src/client/__tests__/sign-in.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,22 @@ jest.mock("../../lib/logger", () => ({

beforeAll(() => {
server.listen()

let _href = window.location.href
// Allows to mutate `window.location`...
delete window.location

window.location = {
...location,
replace: jest.fn(),
reload: jest.fn(),
}
Object.defineProperty(window.location, "href", {
get: () => _href,
// whatwg-fetch or whatwg-url does not seem to work with relative URLs
set: (href) => {
_href = href.startsWith("/") ? `http://localhost${href}` : href
return _href
},
})
})

beforeEach(() => {
Expand All @@ -59,9 +69,10 @@ test.each`
userEvent.click(screen.getByRole("button"))

await waitFor(() => {
expect(window.location.replace).toHaveBeenCalledTimes(1)
expect(window.location.replace).toHaveBeenCalledWith(
`/api/auth/signin?callbackUrl=${encodeURIComponent(callbackUrl)}`
expect(window.location.href).toBe(
`http://localhost/api/auth/signin?${new URLSearchParams({
callbackUrl,
})}`
)
})
}
Expand All @@ -76,14 +87,14 @@ test.each`
async ({ provider }) => {
render(<SignInFlow providerId={provider} />)

const callbackUrl = window.location.href
userEvent.click(screen.getByRole("button"))

await waitFor(() => {
expect(window.location.replace).toHaveBeenCalledTimes(1)
expect(window.location.replace).toHaveBeenCalledWith(
`/api/auth/signin?callbackUrl=${encodeURIComponent(
window.location.href
)}`
expect(window.location.href).toBe(
`http://localhost/api/auth/signin?${new URLSearchParams({
callbackUrl,
})}`
)
})
}
Expand All @@ -101,8 +112,7 @@ test.each`
userEvent.click(screen.getByRole("button"))

await waitFor(() => {
expect(window.location.replace).toHaveBeenCalledTimes(1)
expect(window.location.replace).toHaveBeenCalledWith(mockUrl)
expect(window.location.href).toBe(mockUrl)
})
}
)
Expand All @@ -119,8 +129,7 @@ test("redirection can't be stopped using an oauth provider", async () => {
userEvent.click(screen.getByRole("button"))

await waitFor(() => {
expect(window.location.replace).toHaveBeenCalledTimes(1)
expect(window.location.replace).toHaveBeenCalledWith(mockGithubResponse.url)
expect(window.location.href).toBe(mockGithubResponse.url)
})
})

Expand All @@ -136,9 +145,7 @@ test("redirection can be stopped using the 'credentials' provider", async () =>
userEvent.click(screen.getByRole("button"))

await waitFor(() => {
expect(window.location.replace).not.toHaveBeenCalledWith(
mockCredentialsResponse.url
)
expect(window.location.href).not.toBe(mockCredentialsResponse.url)

expect(screen.getByTestId("signin-result").textContent).not.toBe(
"no response"
Expand All @@ -165,9 +172,7 @@ test("redirection can be stopped using the 'email' provider", async () => {
userEvent.click(screen.getByRole("button"))

await waitFor(() => {
expect(window.location.replace).not.toHaveBeenCalledWith(
mockEmailResponse.url
)
expect(window.location.href).not.toBe(mockEmailResponse.url)

expect(screen.getByTestId("signin-result").textContent).not.toBe(
"no response"
Expand All @@ -190,7 +195,7 @@ test("if callback URL contains a hash we force a window reload when re-directing
const mockUrlWithHash = "https://path/to/email/url#foo-bar-baz"

server.use(
rest.post("/api/auth/signin/email", (req, res, ctx) => {
rest.post("http://localhost/api/auth/signin/email", (req, res, ctx) => {
return res(
ctx.status(200),
ctx.json({
Expand All @@ -206,8 +211,7 @@ test("if callback URL contains a hash we force a window reload when re-directing
userEvent.click(screen.getByRole("button"))

await waitFor(() => {
expect(window.location.replace).toHaveBeenCalledTimes(1)
expect(window.location.replace).toHaveBeenCalledWith(mockUrlWithHash)
expect(window.location.href).toBe(mockUrlWithHash)
// the browser will not refresh the page if the redirect URL contains a hash, hence we force it on the client, see #1289
expect(window.location.reload).toHaveBeenCalledTimes(1)
})
Expand All @@ -218,7 +222,7 @@ test("params are propagated to the signin URL when supplied", async () => {
const authParams = "foo=bar&bar=foo"

server.use(
rest.post("/api/auth/signin/github", (req, res, ctx) => {
rest.post("http://localhost/api/auth/signin/github", (req, res, ctx) => {
matchedParams = req.url.search
return res(ctx.status(200), ctx.json(mockGithubResponse))
})
Expand All @@ -237,7 +241,7 @@ test("when it fails to fetch the providers, it redirected back to signin page",
const errorMsg = "Error when retrieving providers"

server.use(
rest.get("/api/auth/providers", (req, res, ctx) =>
rest.get("http://localhost/api/auth/providers", (req, res, ctx) =>
res(ctx.status(500), ctx.json(errorMsg))
)
)
Expand All @@ -247,7 +251,7 @@ test("when it fails to fetch the providers, it redirected back to signin page",
userEvent.click(screen.getByRole("button"))

await waitFor(() => {
expect(window.location.replace).toHaveBeenCalledWith(`/api/auth/error`)
expect(window.location.href).toBe(`http://localhost/api/auth/error`)

expect(logger.error).toHaveBeenCalledTimes(1)
expect(logger.error).toBeCalledWith("CLIENT_FETCH_ERROR", {
Expand All @@ -268,10 +272,7 @@ function SignInFlow({
async function handleSignIn() {
const result = await signIn(
providerId,
{
callbackUrl,
redirect,
},
{ callbackUrl, redirect },
authorizationParams
)

Expand Down
19 changes: 7 additions & 12 deletions src/client/__tests__/sign-out.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ const { location } = window

beforeAll(() => {
server.listen()
// Allows to mutate `window.location`...
delete window.location
window.location = {
...location,
replace: jest.fn(),
reload: jest.fn(),
href: location.href,
}
})

Expand All @@ -37,7 +37,7 @@ const callbackUrl = "https://redirects/to"

test("by default it redirects to the current URL if the server did not provide one", async () => {
server.use(
rest.post("/api/auth/signout", (req, res, ctx) =>
rest.post("http://localhost/api/auth/signout", (req, res, ctx) =>
res(ctx.status(200), ctx.json({ ...mockSignOutResponse, url: undefined }))
)
)
Expand All @@ -47,8 +47,7 @@ test("by default it redirects to the current URL if the server did not provide o
userEvent.click(screen.getByRole("button"))

await waitFor(() => {
expect(window.location.replace).toHaveBeenCalledTimes(1)
expect(window.location.replace).toHaveBeenCalledWith(window.location.href)
expect(window.location.href).toBe(window.location.href)
})
})

Expand All @@ -58,18 +57,15 @@ test("it redirects to the URL allowed by the server", async () => {
userEvent.click(screen.getByRole("button"))

await waitFor(() => {
expect(window.location.replace).toHaveBeenCalledTimes(1)
expect(window.location.replace).toHaveBeenCalledWith(
mockSignOutResponse.url
)
expect(window.location.href).toBe(mockSignOutResponse.url)
})
})

test("if url contains a hash during redirection a page reload happens", async () => {
const mockUrlWithHash = "https://path/to/email/url#foo-bar-baz"

server.use(
rest.post("/api/auth/signout", (req, res, ctx) => {
rest.post("http://localhost/api/auth/signout", (req, res, ctx) => {
return res(
ctx.status(200),
ctx.json({
Expand All @@ -85,8 +81,7 @@ test("if url contains a hash during redirection a page reload happens", async ()
userEvent.click(screen.getByRole("button"))

await waitFor(() => {
expect(window.location.reload).toHaveBeenCalledTimes(1)
expect(window.location.replace).toHaveBeenCalledWith(mockUrlWithHash)
expect(window.location.href).toBe(mockUrlWithHash)
})
})

Expand Down
Loading