Skip to content

Commit b58bac3

Browse files
authored
test(e2e): add dataset setup and teardown functions for use in CI (#561)
### Description Added dataset setup and teardown functionality for E2E tests, with utilities for managing test datasets. This PR: - Creates a dataset setup script that creates primary and secondary datasets if they don't exist - Adds a dataset teardown script that cleans up test datasets in CI environments (users may want to have their datasets stick around for debugging purposes. we can enforce this differently if things get messy) - Implements helper utilities like `sanityIdify` to create valid Sanity dataset names - Adds a timer utility with visual feedback for long-running operations - Fixes the CI environment variable type to be a boolean instead of string - Normalizes some naming of setup / teardown functions ### What to review - The dataset setup and teardown scripts in `packages/@repo/e2e/src/setup/datasets.setup.ts` and `packages/@repo/e2e/src/teardown/datasets.teardown.ts` - The helper utilities for sanitizing dataset names and timing operations - The type change for the CI environment variable from string to boolean - The dependency changes in package.json files ### Testing You can test this locally by pulling down the branch and updating the following CI variables (please look in 1pass if there's some you don't have): ``` SDK_E2E_DATASET_0=whatever-name SDK_E2E_DATASET_1=whatever-name-2 CI=true SDK_E2E_USER_ID= SDK_E2E_USER_PASSWORD= RECAPTCHA_E2E_STAGING_KEY= ``` and then running `pnpm test:e2e` You should see console logging about creating and destroying datasets. When you go to https://www.sanity.work/organizations/oFvj4MZWQ/project/3j6vt2rg/datasets You shouldn't see the datasets after the tests have run. ### Fun gif ![](https://media1.giphy.com/media/v1.Y2lkPTc5MGI3NjExZmFueXc3NDh6Y3dyZmwyY3ZtbjUwNDlodnB0NWd6YTNnamo0bXlvNyZlcD12MV9naWZzX3NlYXJjaCZjdD1n/dIfpG1Nst0dejPJgyF/giphy.webp)
1 parent 4186e45 commit b58bac3

File tree

10 files changed

+209
-7
lines changed

10 files changed

+209
-7
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
"clean": "run-s clean:build clean:deps",
2626
"clean:build": "turbo run clean",
2727
"clean:deps": "rimraf packages/*/node_modules apps/*/node_modules node_modules",
28+
"cleanup:e2e": "turbo run cleanup --filter=@repo/e2e",
2829
"dev": "pnpm dev:kitchensink",
2930
"dev:kitchensink": "turbo run dev --filter=@sanity/kitchensink-react",
3031
"dev:e2e": "turbo run dev --filter=@sanity/kitchensink-react -- --mode=e2e",

packages/@repo/e2e/package.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,22 +28,27 @@
2828
],
2929
"scripts": {
3030
"build": "pkg build --strict --clean --check",
31+
"cleanup": "tsx src/scripts/cleanup-datasets.ts",
3132
"lint": "eslint .",
3233
"lint:fix": "eslint . --fix",
3334
"prepare": "pnpm build"
3435
},
3536
"dependencies": {
3637
"@sanity/client": "^6.12.5",
3738
"@sanity/uuid": "^3.0.0",
38-
"dotenv": "^16.5.0"
39+
"dotenv": "^16.5.0",
40+
"lodash-es": "^4.17.21",
41+
"ora": "^7.0.1"
3942
},
4043
"devDependencies": {
4144
"@playwright/test": "^1.52.0",
4245
"@repo/config-eslint": "workspace:*",
4346
"@repo/tsconfig": "workspace:*",
4447
"@sanity/pkg-utils": "^7.2.2",
48+
"@types/lodash-es": "^4.17.12",
4549
"@types/node": "^22.10.5",
4650
"eslint": "^9.22.0",
51+
"tsx": "^4.7.1",
4752
"typescript": "^5.0.0"
4853
},
4954
"peerDependencies": {

packages/@repo/e2e/src/helpers/getE2EEnv.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ interface E2EEnv {
1010
/** The session token for authenticated tests */
1111
SDK_E2E_SESSION_TOKEN: string
1212
/** Whether we're running in CI */
13-
CI?: string
13+
CI?: boolean
1414
/** E2E test user ID */
1515
SDK_E2E_USER_ID?: string
1616
/** E2E test user password */
@@ -48,7 +48,7 @@ function findEnv(name: KnownEnvVar): string | undefined {
4848
* Get the E2E environment variables
4949
*/
5050
export function getE2EEnv(): E2EEnv {
51-
const CI = findEnv('CI')
51+
const CI = findEnv('CI') === 'true'
5252
const SDK_E2E_PROJECT_ID = readEnv('SDK_E2E_PROJECT_ID')
5353
const SDK_E2E_DATASET_0 = readEnv('SDK_E2E_DATASET_0')
5454
const SDK_E2E_DATASET_1 = readEnv('SDK_E2E_DATASET_1')
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import {deburr} from 'lodash-es'
2+
3+
// we need to make a valid name for a sanity dataset from inputs
4+
// (people may have odd characters in branch names, etc)
5+
export function sanitizeDatasetName(input: string): string {
6+
return deburr(input)
7+
.replace(/[^a-zA-Z0-9_-]+/g, '_')
8+
.replace(/^-/, '')
9+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import ora from 'ora'
2+
3+
export function startTimer(label: string): {end: () => void} {
4+
const spinner = ora(label).start()
5+
const start = Date.now()
6+
return {
7+
end: () => spinner.succeed(`${label} (${formatMs(Date.now() - start)})`),
8+
}
9+
}
10+
11+
function formatMs(ms: number) {
12+
return ms < 1000 ? `${ms}ms` : `${(ms / 1000).toFixed(2)}s`
13+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#!/usr/bin/env node
2+
3+
/* eslint-disable no-console */
4+
import {getClient} from '../helpers/clients'
5+
import {getE2EEnv} from '../helpers/getE2EEnv'
6+
import {sanitizeDatasetName} from '../helpers/sanitizeDatasetName'
7+
import {startTimer} from '../helpers/timer'
8+
9+
const env = getE2EEnv()
10+
11+
// must be run as a separate script to avoid race conditions with the tests
12+
async function cleanupDatasets() {
13+
const primaryDataset = sanitizeDatasetName(env.SDK_E2E_DATASET_0)
14+
const secondaryDataset = sanitizeDatasetName(env.SDK_E2E_DATASET_1)
15+
16+
const client = getClient()
17+
const timer = startTimer('Cleaning up test datasets')
18+
19+
try {
20+
// Delete primary dataset
21+
try {
22+
await client.datasets.delete(primaryDataset)
23+
console.log(`Successfully deleted primary dataset ${primaryDataset}`)
24+
} catch (error) {
25+
console.error(`Failed to delete primary dataset ${primaryDataset}:`, error)
26+
}
27+
28+
// Delete secondary dataset
29+
try {
30+
await client.datasets.delete(secondaryDataset)
31+
console.log(`Successfully deleted secondary dataset ${secondaryDataset}`)
32+
} catch (error) {
33+
console.error(`Failed to delete secondary dataset ${secondaryDataset}:`, error)
34+
}
35+
36+
timer.end()
37+
} catch (error) {
38+
console.error('Failed to cleanup datasets:', error)
39+
process.exit(1)
40+
}
41+
}
42+
43+
cleanupDatasets().catch((error) => {
44+
console.error('Unhandled error during cleanup:', error)
45+
process.exit(1)
46+
})
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import {test as setup} from '@playwright/test'
2+
3+
import {getClient} from '../helpers/clients'
4+
import {getE2EEnv} from '../helpers/getE2EEnv'
5+
import {sanitizeDatasetName} from '../helpers/sanitizeDatasetName'
6+
import {startTimer} from '../helpers/timer'
7+
8+
const env = getE2EEnv()
9+
10+
setup('setup test datasets', async () => {
11+
const primaryDataset = sanitizeDatasetName(env.SDK_E2E_DATASET_0)
12+
const secondaryDataset = sanitizeDatasetName(env.SDK_E2E_DATASET_1)
13+
14+
const client = getClient()
15+
16+
const datasets = await client.datasets.list()
17+
18+
// Setup primary dataset
19+
if (!datasets.find((ds) => ds.name === primaryDataset)) {
20+
const timer = startTimer(`Creating primary dataset ${primaryDataset}`)
21+
await client.datasets.create(primaryDataset, {
22+
aclMode: 'public',
23+
})
24+
timer.end()
25+
}
26+
27+
// Setup secondary dataset
28+
if (!datasets.find((ds) => ds.name === secondaryDataset)) {
29+
const timer = startTimer(`Creating secondary dataset ${secondaryDataset}`)
30+
await client.datasets.create(secondaryDataset, {
31+
aclMode: 'public',
32+
})
33+
timer.end()
34+
}
35+
})

packages/core/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@
6262
"@sanity/message-protocol": "^0.12.0",
6363
"@sanity/mutate": "^0.12.4",
6464
"@sanity/types": "^3.83.0",
65-
"@types/lodash-es": "^4.17.12",
6665
"groq": "3.88.1-typegen-experimental.0",
6766
"lodash-es": "^4.17.21",
6867
"reselect": "^5.1.1",
@@ -78,6 +77,7 @@
7877
"@sanity/browserslist-config": "^1.0.5",
7978
"@sanity/pkg-utils": "^7.2.2",
8079
"@sanity/prettier-config": "^1.0.3",
80+
"@types/lodash-es": "^4.17.12",
8181
"@vitest/coverage-v8": "3.1.2",
8282
"eslint": "^9.22.0",
8383
"groq-js": "^1.16.1",

0 commit comments

Comments
 (0)