Skip to content

Commit 719b495

Browse files
authored
test(e2e): add functions for logging in via username / password (#554)
* test(e2e): add functions for logging in via username / password * chore(e2e): add a few more notes about the auth / storage state process
1 parent 7a0e07a commit 719b495

File tree

15 files changed

+272
-78
lines changed

15 files changed

+272
-78
lines changed

.github/workflows/depcheck.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,8 @@ jobs:
2828

2929
- name: Depcheck
3030
run: pnpm depcheck
31+
env:
32+
CI: true
33+
SDK_E2E_USER_ID: ${{ secrets.SDK_E2E_USER_ID }}
34+
SDK_E2E_USER_PASSWORD: ${{ secrets.SDK_E2E_USER_PASSWORD }}
35+
RECAPTCHA_E2E_STAGING_KEY: ${{ secrets.RECAPTCHA_E2E_STAGING_KEY }}

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,5 @@ stats
2222

2323
docs
2424
.vitest-reports
25+
26+
.auth

apps/kitchensink-react/e2e/authenticated.spec.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,31 @@
11
// we may want to have our own unauthenticated fixture in the future.
2-
import {test as baseTest} from '@playwright/test'
32
import {expect, test} from '@repo/e2e'
43

54
test.describe('Authenticated', () => {
6-
// This test isn't relevant for most public uses of the SDK,
7-
// but it's useful for working with Playwright tests locally
8-
test('Kitchen sink loads with localStorage auth token', async ({page}) => {
5+
test('Kitchen sink loads when authenticated', async ({page}) => {
96
await page.goto('/')
107

118
// should be able to see the component beneath the AuthBoundary
129
await expect(page.getByTestId('project-auth-home')).toBeVisible()
1310
// Verify we're authenticated by checking for the absence of the sign-in link
1411
await expect(page.getByRole('link', {name: 'Sign in with email'})).not.toBeVisible()
1512
})
13+
})
1614

17-
baseTest('Can test unauthenticated state', async ({page}) => {
15+
// We might go for a dedicated unauthenticated fixture in the future
16+
// rather than just clearing the localStorage
17+
test.describe('Unauthenticated', () => {
18+
test('Can test unauthenticated state', async ({page}) => {
1819
await page.goto('/')
20+
21+
await page.evaluate(() => {
22+
window.localStorage.clear()
23+
})
24+
25+
await page.reload()
26+
27+
// should not be able to see the component beneath the AuthBoundary
28+
await expect(page.getByTestId('project-auth-home')).not.toBeVisible()
1929
// The sign in link should be visible when not authenticated
2030
await expect(page.getByRole('link', {name: 'Sign in with email'})).toBeVisible()
2131
})

apps/kitchensink-react/src/App.tsx

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,14 @@
1-
import {SanityApp, SanityConfig, useDashboardNavigate} from '@sanity/sdk-react'
1+
import {SanityApp, useDashboardNavigate} from '@sanity/sdk-react'
22
import {Spinner, ThemeProvider} from '@sanity/ui'
33
import {buildTheme} from '@sanity/ui/theme'
44
import {type JSX, Suspense} from 'react'
55
import {BrowserRouter, useNavigate} from 'react-router'
66

77
import {AppRoutes} from './AppRoutes'
8+
import {devConfig, e2eConfig} from './sanityConfig'
89

910
const theme = buildTheme({})
1011

11-
const sanityConfigs: SanityConfig[] = [
12-
{
13-
projectId: 'ppsg7ml5',
14-
dataset: 'test',
15-
},
16-
{
17-
projectId: 'd45jg133',
18-
dataset: 'production',
19-
},
20-
]
21-
2212
function NavigationHandler() {
2313
const navigate = useNavigate()
2414
useDashboardNavigate(({path, type}) => {
@@ -30,7 +20,10 @@ function NavigationHandler() {
3020
export default function App(): JSX.Element {
3121
return (
3222
<ThemeProvider theme={theme}>
33-
<SanityApp fallback={<Spinner />} config={sanityConfigs}>
23+
<SanityApp
24+
fallback={<Spinner />}
25+
config={import.meta.env['VITE_IS_CI'] ? e2eConfig : devConfig}
26+
>
3427
<BrowserRouter>
3528
<Suspense>
3629
<NavigationHandler />
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import {type SanityConfig} from '@sanity/sdk-react'
2+
3+
export const devConfig: SanityConfig[] = [
4+
{
5+
projectId: 'ppsg7ml5',
6+
dataset: 'test',
7+
},
8+
{
9+
projectId: 'd45jg133',
10+
dataset: 'production',
11+
},
12+
]
13+
14+
export const e2eConfig: SanityConfig[] = [
15+
{
16+
projectId: '8bzpkfx0',
17+
dataset: 'production',
18+
auth: {
19+
apiHost: 'https://api.sanity.work',
20+
},
21+
},
22+
]

apps/kitchensink-react/vite.config.ts

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,42 @@
11
import {resolve} from 'node:path'
22

33
import react from '@vitejs/plugin-react'
4-
import {defineConfig} from 'vite'
4+
import {defineConfig, loadEnv} from 'vite'
55

66
const ReactCompilerConfig = {
77
target: '18',
88
}
99

10-
export default defineConfig({
11-
server: {
12-
port: 3333,
13-
fs: {
14-
strict: false,
10+
export default defineConfig(({mode}) => {
11+
// load env from root directory of turborepo
12+
const rootDir = resolve(process.cwd(), '../..')
13+
const env = loadEnv(mode, rootDir, '')
14+
15+
return {
16+
server: {
17+
port: 3333,
18+
fs: {
19+
strict: false,
20+
},
1521
},
16-
},
17-
plugins: [
18-
react({
19-
babel: {
20-
plugins: [['babel-plugin-react-compiler', ReactCompilerConfig]],
22+
plugins: [
23+
react({
24+
babel: {
25+
plugins: [['babel-plugin-react-compiler', ReactCompilerConfig]],
26+
},
27+
}),
28+
],
29+
clearScreen: false,
30+
resolve: {
31+
alias: {
32+
'@sanity/sdk': resolve(import.meta.dirname, '../../packages/core/src/_exports'),
33+
'@sanity/sdk-react': resolve(import.meta.dirname, '../../packages/react/src/_exports'),
2134
},
22-
}),
23-
],
24-
clearScreen: false,
25-
resolve: {
26-
alias: {
27-
'@sanity/sdk': resolve(import.meta.dirname, '../../packages/core/src/_exports'),
28-
'@sanity/sdk-react': resolve(import.meta.dirname, '../../packages/react/src/_exports'),
2935
},
30-
},
36+
define: {
37+
'import.meta.env.VITE_IS_CI': JSON.stringify(
38+
process.env['CI'] === 'true' || env['CI'] === 'true',
39+
),
40+
},
41+
}
3142
})

knip.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ const baseConfig = {
6161
config: 'tsconfig.json',
6262
},
6363
project,
64+
entry: ['src/index.ts', 'src/setup/**/*.ts', 'src/teardown/**/*.ts'],
6465
ignoreDependencies: ['@repo/tsconfig'],
6566
},
6667
},

packages/@repo/e2e/README.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ To run E2E tests run the following commands from the root of the project
1919
- Run files that have my-spec or my-spec-2 in the file name
2020

2121
```sh
22-
pnpm test:e2e my-spec my-spec-2
22+
pnpm test:e2e -- my-spec my-spec-2
2323
```
2424

2525
- For help, run
@@ -36,3 +36,12 @@ For more useful commands, see the [Playwright Command Line](https://playwright.d
3636
### Running tests from your code editor
3737

3838
You can run your tests in your editor with the help of some useful editor plugins/extensions. For example, you can download `Playwright Test for VSCode` from Microsoft to show and run your tests in VSCode.
39+
40+
### Running in CI mode
41+
42+
These tests run in CI with a dedicated e2e test user. If you'd like to replicate that, you should add the following variables to your .env.local file:
43+
44+
- `CI`: true
45+
- `SDK_E2E_USER_ID`: [email protected]
46+
- `SDK_E2E_USER_PASSWORD` (found in 1Password under "SDK e2e user Sanity login")
47+
- `RECAPTCHA_E2E_STAGING_KEY` (found in 1Password under "Legion E2E staging reCAPTCHA bypass token")

packages/@repo/e2e/src/env.ts

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,20 @@
11
import {loadEnvFiles} from './helpers/loadEnvFiles'
22

3-
/**
4-
* Environment variables for E2E tests
5-
*/
6-
type KnownEnvVar = 'SDK_E2E_SESSION_TOKEN' | 'CI'
7-
83
interface E2EEnv {
94
/** The session token for authenticated tests */
105
SDK_E2E_SESSION_TOKEN?: string
116
/** Whether we're running in CI */
127
CI?: string
8+
/** E2E test user ID */
9+
SDK_E2E_USER_ID?: string
10+
/** E2E test user password */
11+
SDK_E2E_USER_PASSWORD?: string
12+
/** E2E test recaptcha key for CI */
13+
RECAPTCHA_E2E_STAGING_KEY?: string
1314
}
1415

16+
type KnownEnvVar = keyof E2EEnv
17+
1518
loadEnvFiles()
1619

1720
/**
@@ -37,11 +40,22 @@ function findEnv(name: KnownEnvVar): string | undefined {
3740
export function getE2EEnv(): E2EEnv {
3841
const CI = findEnv('CI')
3942
let SDK_E2E_SESSION_TOKEN: string | undefined
40-
if (!CI) {
43+
let SDK_E2E_USER_ID: string | undefined
44+
let SDK_E2E_USER_PASSWORD: string | undefined
45+
let RECAPTCHA_E2E_STAGING_KEY: string | undefined
46+
if (CI) {
47+
SDK_E2E_USER_ID = readEnv('SDK_E2E_USER_ID')
48+
SDK_E2E_USER_PASSWORD = readEnv('SDK_E2E_USER_PASSWORD')
49+
RECAPTCHA_E2E_STAGING_KEY = readEnv('RECAPTCHA_E2E_STAGING_KEY')
50+
} else {
4151
SDK_E2E_SESSION_TOKEN = readEnv('SDK_E2E_SESSION_TOKEN')
4252
}
53+
4354
return {
4455
SDK_E2E_SESSION_TOKEN,
4556
CI,
57+
SDK_E2E_USER_ID,
58+
SDK_E2E_USER_PASSWORD,
59+
RECAPTCHA_E2E_STAGING_KEY,
4660
}
4761
}

packages/@repo/e2e/src/fixtures.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import {test as base} from '@playwright/test'
2+
3+
/**
4+
* @internal
5+
* Playwright test configuration for SDK E2E tests
6+
* (If different apps diverge dramatically, we can move this logic)
7+
*/
8+
export const test = base.extend({
9+
// We'll add custom fixtures shortly
10+
})
11+
12+
export {expect} from '@playwright/test'

0 commit comments

Comments
 (0)