rwsdk 1.0.0-beta.1 → 1.0.0-beta.11
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/dist/lib/e2e/constants.d.mts +13 -0
- package/dist/lib/e2e/constants.mjs +67 -0
- package/dist/lib/e2e/environment.d.mts +1 -1
- package/dist/lib/e2e/environment.mjs +16 -6
- package/dist/lib/e2e/index.d.mts +1 -0
- package/dist/lib/e2e/index.mjs +1 -0
- package/dist/lib/e2e/testHarness.d.mts +33 -3
- package/dist/lib/e2e/testHarness.mjs +181 -109
- package/dist/runtime/client/client.d.ts +1 -0
- package/dist/runtime/client/client.js +2 -0
- package/dist/runtime/client/navigation.d.ts +8 -0
- package/dist/runtime/client/navigation.js +39 -31
- package/dist/runtime/entries/clientSSR.d.ts +1 -0
- package/dist/runtime/entries/clientSSR.js +3 -0
- package/dist/runtime/lib/db/createDb.d.ts +1 -2
- package/dist/runtime/lib/db/createDb.js +4 -0
- package/dist/runtime/lib/manifest.d.ts +1 -1
- package/dist/runtime/lib/manifest.js +7 -4
- package/dist/runtime/lib/realtime/client.js +8 -2
- package/dist/runtime/lib/router.d.ts +1 -19
- package/dist/runtime/lib/router.test.js +2 -0
- package/dist/runtime/lib/{rwContext.d.ts → types.d.ts} +1 -0
- package/dist/runtime/render/renderDocumentHtmlStream.d.ts +1 -1
- package/dist/runtime/render/renderToStream.d.ts +1 -1
- package/dist/runtime/render/renderToString.d.ts +1 -1
- package/dist/runtime/requestInfo/types.d.ts +1 -1
- package/dist/runtime/script.d.ts +1 -3
- package/dist/runtime/script.js +1 -10
- package/dist/runtime/worker.js +25 -0
- package/dist/scripts/addon.mjs +1 -1
- package/dist/scripts/smoke-test.mjs +4 -2
- package/dist/scripts/worker-run.d.mts +1 -1
- package/dist/scripts/worker-run.mjs +50 -113
- package/dist/vite/buildApp.mjs +2 -0
- package/dist/vite/directiveModulesDevPlugin.mjs +1 -1
- package/dist/vite/linkerPlugin.mjs +1 -1
- package/dist/vite/redwoodPlugin.mjs +0 -4
- package/dist/vite/runDirectivesScan.mjs +57 -12
- package/package.json +9 -7
- package/dist/vite/manifestPlugin.d.mts +0 -4
- package/dist/vite/manifestPlugin.mjs +0 -63
- /package/dist/runtime/lib/{rwContext.js → types.js} +0 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare const IS_DEBUG_MODE: string | boolean;
|
|
2
|
+
export declare const SETUP_PLAYGROUND_ENV_TIMEOUT: number;
|
|
3
|
+
export declare const DEPLOYMENT_TIMEOUT: number;
|
|
4
|
+
export declare const DEPLOYMENT_MIN_TRIES: number;
|
|
5
|
+
export declare const DEPLOYMENT_CHECK_TIMEOUT: number;
|
|
6
|
+
export declare const PUPPETEER_TIMEOUT: number;
|
|
7
|
+
export declare const HYDRATION_TIMEOUT: number;
|
|
8
|
+
export declare const DEV_SERVER_TIMEOUT: number;
|
|
9
|
+
export declare const DEV_SERVER_MIN_TRIES: number;
|
|
10
|
+
export declare const SETUP_WAIT_TIMEOUT: number;
|
|
11
|
+
export declare const TEST_MAX_RETRIES: number;
|
|
12
|
+
export declare const TEST_MAX_RETRIES_PER_CODE: number;
|
|
13
|
+
export declare const INSTALL_DEPENDENCIES_RETRIES: number;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
export const IS_DEBUG_MODE = process.env.RWSDK_E2E_DEBUG
|
|
2
|
+
? process.env.RWSDK_E2E_DEBUG
|
|
3
|
+
: !process.env.CI;
|
|
4
|
+
export const SETUP_PLAYGROUND_ENV_TIMEOUT = process.env
|
|
5
|
+
.RWSDK_SETUP_PLAYGROUND_ENV_TIMEOUT
|
|
6
|
+
? parseInt(process.env.RWSDK_SETUP_PLAYGROUND_ENV_TIMEOUT, 10)
|
|
7
|
+
: IS_DEBUG_MODE
|
|
8
|
+
? 10 * 60 * 1000
|
|
9
|
+
: 15 * 60 * 1000;
|
|
10
|
+
export const DEPLOYMENT_TIMEOUT = process.env.RWSDK_DEPLOYMENT_TIMEOUT
|
|
11
|
+
? parseInt(process.env.RWSDK_DEPLOYMENT_TIMEOUT, 10)
|
|
12
|
+
: IS_DEBUG_MODE
|
|
13
|
+
? 5 * 30 * 1000
|
|
14
|
+
: 5 * 60 * 1000;
|
|
15
|
+
export const DEPLOYMENT_MIN_TRIES = process.env.RWSDK_DEPLOYMENT_MIN_TRIES
|
|
16
|
+
? parseInt(process.env.RWSDK_DEPLOYMENT_MIN_TRIES, 10)
|
|
17
|
+
: IS_DEBUG_MODE
|
|
18
|
+
? 1
|
|
19
|
+
: 5;
|
|
20
|
+
export const DEPLOYMENT_CHECK_TIMEOUT = process.env
|
|
21
|
+
.RWSDK_DEPLOYMENT_CHECK_TIMEOUT
|
|
22
|
+
? parseInt(process.env.RWSDK_DEPLOYMENT_CHECK_TIMEOUT, 10)
|
|
23
|
+
: IS_DEBUG_MODE
|
|
24
|
+
? 30 * 1000
|
|
25
|
+
: 5 * 60 * 1000;
|
|
26
|
+
export const PUPPETEER_TIMEOUT = process.env.RWSDK_PUPPETEER_TIMEOUT
|
|
27
|
+
? parseInt(process.env.RWSDK_PUPPETEER_TIMEOUT, 10)
|
|
28
|
+
: IS_DEBUG_MODE
|
|
29
|
+
? 30 * 1000
|
|
30
|
+
: 60 * 1000 * 2;
|
|
31
|
+
export const HYDRATION_TIMEOUT = process.env.RWSDK_HYDRATION_TIMEOUT
|
|
32
|
+
? parseInt(process.env.RWSDK_HYDRATION_TIMEOUT, 10)
|
|
33
|
+
: IS_DEBUG_MODE
|
|
34
|
+
? 2000
|
|
35
|
+
: 5000;
|
|
36
|
+
export const DEV_SERVER_TIMEOUT = process.env.RWSDK_DEV_SERVER_TIMEOUT
|
|
37
|
+
? parseInt(process.env.RWSDK_DEV_SERVER_TIMEOUT, 10)
|
|
38
|
+
: IS_DEBUG_MODE
|
|
39
|
+
? 60 * 1000
|
|
40
|
+
: 5 * 60 * 1000;
|
|
41
|
+
export const DEV_SERVER_MIN_TRIES = process.env.RWSDK_DEV_SERVER_MIN_TRIES
|
|
42
|
+
? parseInt(process.env.RWSDK_DEV_SERVER_MIN_TRIES, 10)
|
|
43
|
+
: IS_DEBUG_MODE
|
|
44
|
+
? 1
|
|
45
|
+
: 5;
|
|
46
|
+
export const SETUP_WAIT_TIMEOUT = process.env.RWSDK_SETUP_WAIT_TIMEOUT
|
|
47
|
+
? parseInt(process.env.RWSDK_SETUP_WAIT_TIMEOUT, 10)
|
|
48
|
+
: IS_DEBUG_MODE
|
|
49
|
+
? 60 * 1000
|
|
50
|
+
: 10 * 60 * 1000;
|
|
51
|
+
export const TEST_MAX_RETRIES = process.env.RWSDK_TEST_MAX_RETRIES
|
|
52
|
+
? parseInt(process.env.RWSDK_TEST_MAX_RETRIES, 10)
|
|
53
|
+
: IS_DEBUG_MODE
|
|
54
|
+
? 1
|
|
55
|
+
: 10;
|
|
56
|
+
export const TEST_MAX_RETRIES_PER_CODE = process.env
|
|
57
|
+
.RWSDK_TEST_MAX_RETRIES_PER_CODE
|
|
58
|
+
? parseInt(process.env.RWSDK_TEST_MAX_RETRIES_PER_CODE, 10)
|
|
59
|
+
: IS_DEBUG_MODE
|
|
60
|
+
? 0
|
|
61
|
+
: 6;
|
|
62
|
+
export const INSTALL_DEPENDENCIES_RETRIES = process.env
|
|
63
|
+
.RWSDK_INSTALL_DEPENDENCIES_RETRIES
|
|
64
|
+
? parseInt(process.env.RWSDK_INSTALL_DEPENDENCIES_RETRIES, 10)
|
|
65
|
+
: IS_DEBUG_MODE
|
|
66
|
+
? 1
|
|
67
|
+
: 10;
|
|
@@ -3,7 +3,7 @@ import { PackageManager } from "./types.mjs";
|
|
|
3
3
|
/**
|
|
4
4
|
* Copy project to a temporary directory with a unique name
|
|
5
5
|
*/
|
|
6
|
-
export declare function copyProjectToTempDir(projectDir: string, resourceUniqueKey: string, packageManager?: PackageManager, monorepoRoot?: string): Promise<{
|
|
6
|
+
export declare function copyProjectToTempDir(projectDir: string, resourceUniqueKey: string, packageManager?: PackageManager, monorepoRoot?: string, installDependenciesRetries?: number): Promise<{
|
|
7
7
|
tempDir: tmp.DirectoryResult;
|
|
8
8
|
targetDir: string;
|
|
9
9
|
workerName: string;
|
|
@@ -8,8 +8,12 @@ import { basename, join, relative, resolve } from "path";
|
|
|
8
8
|
import tmp from "tmp-promise";
|
|
9
9
|
import { $ } from "../../lib/$.mjs";
|
|
10
10
|
import { ROOT_DIR } from "../constants.mjs";
|
|
11
|
+
import { INSTALL_DEPENDENCIES_RETRIES } from "./constants.mjs";
|
|
11
12
|
import { retry } from "./retry.mjs";
|
|
12
13
|
const log = debug("rwsdk:e2e:environment");
|
|
14
|
+
const getTempDir = async () => {
|
|
15
|
+
return tmp.dir({ unsafeCleanup: true });
|
|
16
|
+
};
|
|
13
17
|
const createSdkTarball = async () => {
|
|
14
18
|
const existingTarballPath = process.env.RWSKD_SMOKE_TEST_TARBALL_PATH;
|
|
15
19
|
if (existingTarballPath) {
|
|
@@ -46,12 +50,11 @@ const setTarballDependency = async (targetDir, tarballName) => {
|
|
|
46
50
|
/**
|
|
47
51
|
* Copy project to a temporary directory with a unique name
|
|
48
52
|
*/
|
|
49
|
-
export async function copyProjectToTempDir(projectDir, resourceUniqueKey, packageManager, monorepoRoot) {
|
|
53
|
+
export async function copyProjectToTempDir(projectDir, resourceUniqueKey, packageManager, monorepoRoot, installDependenciesRetries) {
|
|
50
54
|
const { tarballPath, cleanupTarball } = await createSdkTarball();
|
|
51
55
|
try {
|
|
52
56
|
log("Creating temporary directory for project");
|
|
53
|
-
|
|
54
|
-
const tempDir = await tmp.dir({ unsafeCleanup: true });
|
|
57
|
+
const tempDir = await getTempDir();
|
|
55
58
|
// Determine the source directory to copy from
|
|
56
59
|
const sourceDir = monorepoRoot || projectDir;
|
|
57
60
|
// Create unique project directory name
|
|
@@ -130,7 +133,6 @@ export async function copyProjectToTempDir(projectDir, resourceUniqueKey, packag
|
|
|
130
133
|
log("⚙️ Configuring temp project to not use frozen lockfile...");
|
|
131
134
|
const npmrcPath = join(targetDir, ".npmrc");
|
|
132
135
|
await fs.promises.writeFile(npmrcPath, "frozen-lockfile=false\n");
|
|
133
|
-
// For yarn, create .yarnrc.yml to disable PnP and allow lockfile changes
|
|
134
136
|
if (packageManager === "yarn") {
|
|
135
137
|
const yarnrcPath = join(targetDir, ".yarnrc.yml");
|
|
136
138
|
const yarnCacheDir = path.join(os.tmpdir(), "yarn-cache");
|
|
@@ -144,11 +146,19 @@ export async function copyProjectToTempDir(projectDir, resourceUniqueKey, packag
|
|
|
144
146
|
await fs.promises.writeFile(yarnrcPath, yarnConfig);
|
|
145
147
|
log("Created .yarnrc.yml to allow lockfile changes for yarn");
|
|
146
148
|
}
|
|
149
|
+
if (packageManager === "yarn-classic") {
|
|
150
|
+
const yarnrcPath = join(targetDir, ".yarnrc");
|
|
151
|
+
const yarnCacheDir = path.join(os.tmpdir(), "yarn-classic-cache");
|
|
152
|
+
await fs.promises.mkdir(yarnCacheDir, { recursive: true });
|
|
153
|
+
const yarnConfig = `cache-folder "${yarnCacheDir}"`;
|
|
154
|
+
await fs.promises.writeFile(yarnrcPath, yarnConfig);
|
|
155
|
+
log("Created .yarnrc with cache-folder for yarn-classic");
|
|
156
|
+
}
|
|
147
157
|
await setTarballDependency(targetDir, tarballFilename);
|
|
148
158
|
// Install dependencies in the target directory
|
|
149
159
|
const installDir = monorepoRoot ? tempCopyRoot : targetDir;
|
|
150
160
|
await retry(() => installDependencies(installDir, packageManager), {
|
|
151
|
-
retries:
|
|
161
|
+
retries: INSTALL_DEPENDENCIES_RETRIES,
|
|
152
162
|
delay: 1000,
|
|
153
163
|
});
|
|
154
164
|
// Return the environment details
|
|
@@ -185,7 +195,7 @@ async function installDependencies(targetDir, packageManager = "pnpm") {
|
|
|
185
195
|
}
|
|
186
196
|
else if (packageManager === "yarn-classic") {
|
|
187
197
|
log(`Preparing yarn@1.22.19 with corepack...`);
|
|
188
|
-
await $("corepack", ["prepare", "yarn@1.
|
|
198
|
+
await $("corepack", ["prepare", "yarn@1.x", "--activate"], {
|
|
189
199
|
cwd: targetDir,
|
|
190
200
|
stdio: "pipe",
|
|
191
201
|
});
|
package/dist/lib/e2e/index.d.mts
CHANGED
package/dist/lib/e2e/index.mjs
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { type Browser, type Page } from "puppeteer-core";
|
|
2
2
|
import { test } from "vitest";
|
|
3
|
+
import { DEPLOYMENT_CHECK_TIMEOUT, DEPLOYMENT_MIN_TRIES, DEPLOYMENT_TIMEOUT, DEV_SERVER_MIN_TRIES, DEV_SERVER_TIMEOUT, HYDRATION_TIMEOUT, INSTALL_DEPENDENCIES_RETRIES, PUPPETEER_TIMEOUT, SETUP_PLAYGROUND_ENV_TIMEOUT, SETUP_WAIT_TIMEOUT, TEST_MAX_RETRIES, TEST_MAX_RETRIES_PER_CODE } from "./constants.mjs";
|
|
3
4
|
export type { Browser, Page } from "puppeteer-core";
|
|
5
|
+
export { DEPLOYMENT_CHECK_TIMEOUT, DEPLOYMENT_MIN_TRIES, DEPLOYMENT_TIMEOUT, DEV_SERVER_MIN_TRIES, DEV_SERVER_TIMEOUT, HYDRATION_TIMEOUT, INSTALL_DEPENDENCIES_RETRIES, PUPPETEER_TIMEOUT, SETUP_PLAYGROUND_ENV_TIMEOUT, SETUP_WAIT_TIMEOUT, TEST_MAX_RETRIES, TEST_MAX_RETRIES_PER_CODE, };
|
|
4
6
|
interface DevServerInstance {
|
|
5
7
|
url: string;
|
|
8
|
+
projectDir: string;
|
|
6
9
|
stopDev: () => Promise<void>;
|
|
7
10
|
}
|
|
8
11
|
interface DeploymentInstance {
|
|
@@ -41,17 +44,29 @@ export interface SetupPlaygroundEnvironmentOptions {
|
|
|
41
44
|
* and installs dependencies using a tarball of the SDK.
|
|
42
45
|
* This ensures that tests run in a clean, isolated environment.
|
|
43
46
|
*/
|
|
44
|
-
export declare function setupPlaygroundEnvironment(options
|
|
47
|
+
export declare function setupPlaygroundEnvironment(options: SetupPlaygroundEnvironmentOptions | string): void;
|
|
45
48
|
/**
|
|
46
49
|
* Creates a dev server instance using the shared playground environment.
|
|
47
50
|
* Automatically registers cleanup to run after the test.
|
|
48
51
|
*/
|
|
49
|
-
export declare function createDevServer(
|
|
52
|
+
export declare function createDevServer(): {
|
|
53
|
+
projectDir: string;
|
|
54
|
+
start: () => Promise<DevServerInstance>;
|
|
55
|
+
};
|
|
50
56
|
/**
|
|
51
57
|
* Creates a deployment instance using the shared playground environment.
|
|
52
58
|
* Automatically registers cleanup to run after the test.
|
|
53
59
|
*/
|
|
54
|
-
export declare function createDeployment(
|
|
60
|
+
export declare function createDeployment(): {
|
|
61
|
+
projectDir: string;
|
|
62
|
+
start: () => Promise<{
|
|
63
|
+
url: string;
|
|
64
|
+
workerName: string;
|
|
65
|
+
resourceUniqueKey: string;
|
|
66
|
+
projectDir: string;
|
|
67
|
+
cleanup: () => Promise<void>;
|
|
68
|
+
}>;
|
|
69
|
+
};
|
|
55
70
|
/**
|
|
56
71
|
* Executes a test function with a retry mechanism for specific error codes.
|
|
57
72
|
* @param name - The name of the test, used for logging.
|
|
@@ -61,13 +76,25 @@ export declare function createDeployment(projectDir: string): Promise<Deployment
|
|
|
61
76
|
* called automatically on failure.
|
|
62
77
|
*/
|
|
63
78
|
export declare function runTestWithRetries(name: string, attemptFn: () => Promise<void>): Promise<void>;
|
|
79
|
+
type SDKRunner = (name: string, testLogic: (context: {
|
|
80
|
+
createDevServer: () => Promise<DevServerInstance>;
|
|
81
|
+
createDeployment: () => Promise<DeploymentInstance>;
|
|
82
|
+
browser: Browser;
|
|
83
|
+
page: Page;
|
|
84
|
+
projectDir: string;
|
|
85
|
+
}) => Promise<void>) => void;
|
|
64
86
|
declare function createTestRunner(testFn: (typeof test | typeof test.only)["concurrent"], envType: "dev" | "deploy"): (name: string, testLogic: (context: {
|
|
65
87
|
devServer?: DevServerInstance;
|
|
66
88
|
deployment?: DeploymentInstance;
|
|
67
89
|
browser: Browser;
|
|
68
90
|
page: Page;
|
|
69
91
|
url: string;
|
|
92
|
+
projectDir: string;
|
|
70
93
|
}) => Promise<void>) => void;
|
|
94
|
+
export declare const testSDK: SDKRunner & {
|
|
95
|
+
only: SDKRunner;
|
|
96
|
+
skip: typeof test.skip;
|
|
97
|
+
};
|
|
71
98
|
/**
|
|
72
99
|
* High-level test wrapper for dev server tests.
|
|
73
100
|
* Automatically skips if RWSDK_SKIP_DEV=1
|
|
@@ -81,6 +108,7 @@ export declare namespace testDev {
|
|
|
81
108
|
browser: Browser;
|
|
82
109
|
page: Page;
|
|
83
110
|
url: string;
|
|
111
|
+
projectDir: string;
|
|
84
112
|
}) => Promise<void>) => void;
|
|
85
113
|
}
|
|
86
114
|
/**
|
|
@@ -96,6 +124,7 @@ export declare namespace testDeploy {
|
|
|
96
124
|
browser: Browser;
|
|
97
125
|
page: Page;
|
|
98
126
|
url: string;
|
|
127
|
+
projectDir: string;
|
|
99
128
|
}) => Promise<void>) => void;
|
|
100
129
|
}
|
|
101
130
|
/**
|
|
@@ -108,6 +137,7 @@ export declare function testDevAndDeploy(name: string, testFn: (context: {
|
|
|
108
137
|
browser: Browser;
|
|
109
138
|
page: Page;
|
|
110
139
|
url: string;
|
|
140
|
+
projectDir: string;
|
|
111
141
|
}) => Promise<void>): void;
|
|
112
142
|
export declare namespace testDevAndDeploy {
|
|
113
143
|
var skip: (name: string, testFn?: any) => void;
|
|
@@ -4,44 +4,12 @@ import path, { basename, dirname, join as pathJoin } from "path";
|
|
|
4
4
|
import puppeteer from "puppeteer-core";
|
|
5
5
|
import { afterAll, afterEach, beforeAll, beforeEach, describe, test, } from "vitest";
|
|
6
6
|
import { launchBrowser } from "./browser.mjs";
|
|
7
|
+
import { DEPLOYMENT_CHECK_TIMEOUT, DEPLOYMENT_MIN_TRIES, DEPLOYMENT_TIMEOUT, DEV_SERVER_MIN_TRIES, DEV_SERVER_TIMEOUT, HYDRATION_TIMEOUT, INSTALL_DEPENDENCIES_RETRIES, PUPPETEER_TIMEOUT, SETUP_PLAYGROUND_ENV_TIMEOUT, SETUP_WAIT_TIMEOUT, TEST_MAX_RETRIES, TEST_MAX_RETRIES_PER_CODE, } from "./constants.mjs";
|
|
7
8
|
import { runDevServer } from "./dev.mjs";
|
|
8
9
|
import { poll, pollValue } from "./poll.mjs";
|
|
9
10
|
import { deleteD1Database, deleteWorker, isRelatedToTest, runRelease, } from "./release.mjs";
|
|
10
11
|
import { setupTarballEnvironment } from "./tarball.mjs";
|
|
11
|
-
|
|
12
|
-
.RWSDK_SETUP_PLAYGROUND_ENV_TIMEOUT
|
|
13
|
-
? parseInt(process.env.RWSDK_SETUP_PLAYGROUND_ENV_TIMEOUT, 10)
|
|
14
|
-
: 15 * 60 * 1000;
|
|
15
|
-
const DEPLOYMENT_TIMEOUT = process.env.RWSDK_DEPLOYMENT_TIMEOUT
|
|
16
|
-
? parseInt(process.env.RWSDK_DEPLOYMENT_TIMEOUT, 10)
|
|
17
|
-
: 5 * 60 * 1000;
|
|
18
|
-
const DEPLOYMENT_MIN_TRIES = process.env.RWSDK_DEPLOYMENT_MIN_TRIES
|
|
19
|
-
? parseInt(process.env.RWSDK_DEPLOYMENT_MIN_TRIES, 10)
|
|
20
|
-
: 5;
|
|
21
|
-
const DEPLOYMENT_CHECK_TIMEOUT = process.env.RWSDK_DEPLOYMENT_CHECK_TIMEOUT
|
|
22
|
-
? parseInt(process.env.RWSDK_DEPLOYMENT_CHECK_TIMEOUT, 10)
|
|
23
|
-
: 5 * 60 * 1000;
|
|
24
|
-
const PUPPETEER_TIMEOUT = process.env.RWSDK_PUPPETEER_TIMEOUT
|
|
25
|
-
? parseInt(process.env.RWSDK_PUPPETEER_TIMEOUT, 10)
|
|
26
|
-
: 60 * 1000 * 2;
|
|
27
|
-
const HYDRATION_TIMEOUT = process.env.RWSDK_HYDRATION_TIMEOUT
|
|
28
|
-
? parseInt(process.env.RWSDK_HYDRATION_TIMEOUT, 10)
|
|
29
|
-
: 5000;
|
|
30
|
-
const DEV_SERVER_TIMEOUT = process.env.RWSDK_DEV_SERVER_TIMEOUT
|
|
31
|
-
? parseInt(process.env.RWSDK_DEV_SERVER_TIMEOUT, 10)
|
|
32
|
-
: 5 * 60 * 1000;
|
|
33
|
-
const DEV_SERVER_MIN_TRIES = process.env.RWSDK_DEV_SERVER_MIN_TRIES
|
|
34
|
-
? parseInt(process.env.RWSDK_DEV_SERVER_MIN_TRIES, 10)
|
|
35
|
-
: 5;
|
|
36
|
-
const SETUP_WAIT_TIMEOUT = process.env.RWSDK_SETUP_WAIT_TIMEOUT
|
|
37
|
-
? parseInt(process.env.RWSDK_SETUP_WAIT_TIMEOUT, 10)
|
|
38
|
-
: 10 * 60 * 1000;
|
|
39
|
-
const TEST_MAX_RETRIES = process.env.RWSDK_TEST_MAX_RETRIES
|
|
40
|
-
? parseInt(process.env.RWSDK_TEST_MAX_RETRIES, 10)
|
|
41
|
-
: 10;
|
|
42
|
-
const TEST_MAX_RETRIES_PER_CODE = process.env.RWSDK_TEST_MAX_RETRIES_PER_CODE
|
|
43
|
-
? parseInt(process.env.RWSDK_TEST_MAX_RETRIES_PER_CODE, 10)
|
|
44
|
-
: 6;
|
|
12
|
+
export { DEPLOYMENT_CHECK_TIMEOUT, DEPLOYMENT_MIN_TRIES, DEPLOYMENT_TIMEOUT, DEV_SERVER_MIN_TRIES, DEV_SERVER_TIMEOUT, HYDRATION_TIMEOUT, INSTALL_DEPENDENCIES_RETRIES, PUPPETEER_TIMEOUT, SETUP_PLAYGROUND_ENV_TIMEOUT, SETUP_WAIT_TIMEOUT, TEST_MAX_RETRIES, TEST_MAX_RETRIES_PER_CODE, };
|
|
45
13
|
// Environment variable flags for skipping tests
|
|
46
14
|
const SKIP_DEV_SERVER_TESTS = process.env.RWSDK_SKIP_DEV === "1";
|
|
47
15
|
const SKIP_DEPLOYMENT_TESTS = process.env.RWSDK_SKIP_DEPLOY === "1";
|
|
@@ -52,6 +20,8 @@ let globalDevInstancePromise = null;
|
|
|
52
20
|
let globalDeploymentInstancePromise = null;
|
|
53
21
|
let globalDevInstance = null;
|
|
54
22
|
let globalDeploymentInstance = null;
|
|
23
|
+
const devInstances = [];
|
|
24
|
+
const deploymentInstances = [];
|
|
55
25
|
let hooksRegistered = false;
|
|
56
26
|
/**
|
|
57
27
|
* Registers global cleanup hooks automatically
|
|
@@ -62,11 +32,11 @@ function ensureHooksRegistered() {
|
|
|
62
32
|
// Register global afterAll to clean up the playground environment
|
|
63
33
|
afterAll(async () => {
|
|
64
34
|
const cleanupPromises = [];
|
|
65
|
-
|
|
66
|
-
cleanupPromises.push(
|
|
35
|
+
for (const instance of devInstances) {
|
|
36
|
+
cleanupPromises.push(instance.stopDev());
|
|
67
37
|
}
|
|
68
|
-
|
|
69
|
-
cleanupPromises.push(
|
|
38
|
+
for (const instance of deploymentInstances) {
|
|
39
|
+
cleanupPromises.push(instance.cleanup());
|
|
70
40
|
}
|
|
71
41
|
if (globalDevPlaygroundEnv) {
|
|
72
42
|
cleanupPromises.push(globalDevPlaygroundEnv.cleanup());
|
|
@@ -75,8 +45,8 @@ function ensureHooksRegistered() {
|
|
|
75
45
|
cleanupPromises.push(globalDeployPlaygroundEnv.cleanup());
|
|
76
46
|
}
|
|
77
47
|
await Promise.all(cleanupPromises);
|
|
78
|
-
|
|
79
|
-
|
|
48
|
+
devInstances.length = 0;
|
|
49
|
+
deploymentInstances.length = 0;
|
|
80
50
|
globalDevPlaygroundEnv = null;
|
|
81
51
|
globalDeployPlaygroundEnv = null;
|
|
82
52
|
});
|
|
@@ -114,7 +84,7 @@ function getPlaygroundDirFromImportMeta(importMetaUrl) {
|
|
|
114
84
|
* and installs dependencies using a tarball of the SDK.
|
|
115
85
|
* This ensures that tests run in a clean, isolated environment.
|
|
116
86
|
*/
|
|
117
|
-
export function setupPlaygroundEnvironment(options
|
|
87
|
+
export function setupPlaygroundEnvironment(options) {
|
|
118
88
|
const { sourceProjectDir, monorepoRoot, dev = true, deploy = true, } = typeof options === "string" ? { sourceProjectDir: options } : options;
|
|
119
89
|
ensureHooksRegistered();
|
|
120
90
|
beforeAll(async () => {
|
|
@@ -141,7 +111,8 @@ export function setupPlaygroundEnvironment(options = {}) {
|
|
|
141
111
|
projectDir: devEnv.targetDir,
|
|
142
112
|
cleanup: devEnv.cleanup,
|
|
143
113
|
};
|
|
144
|
-
|
|
114
|
+
const devControl = createDevServer();
|
|
115
|
+
globalDevInstancePromise = devControl.start().then((instance) => {
|
|
145
116
|
globalDevInstance = instance;
|
|
146
117
|
return instance;
|
|
147
118
|
});
|
|
@@ -150,7 +121,7 @@ export function setupPlaygroundEnvironment(options = {}) {
|
|
|
150
121
|
globalDevInstancePromise.catch(() => { });
|
|
151
122
|
}
|
|
152
123
|
else {
|
|
153
|
-
|
|
124
|
+
globalDevPlaygroundEnv = null;
|
|
154
125
|
}
|
|
155
126
|
if (deploy) {
|
|
156
127
|
const deployEnv = await setupTarballEnvironment({
|
|
@@ -162,7 +133,10 @@ export function setupPlaygroundEnvironment(options = {}) {
|
|
|
162
133
|
projectDir: deployEnv.targetDir,
|
|
163
134
|
cleanup: deployEnv.cleanup,
|
|
164
135
|
};
|
|
165
|
-
|
|
136
|
+
const deployControl = createDeployment();
|
|
137
|
+
globalDeploymentInstancePromise = deployControl
|
|
138
|
+
.start()
|
|
139
|
+
.then((instance) => {
|
|
166
140
|
globalDeploymentInstance = instance;
|
|
167
141
|
return instance;
|
|
168
142
|
});
|
|
@@ -170,7 +144,7 @@ export function setupPlaygroundEnvironment(options = {}) {
|
|
|
170
144
|
globalDeploymentInstancePromise.catch(() => { });
|
|
171
145
|
}
|
|
172
146
|
else {
|
|
173
|
-
|
|
147
|
+
globalDeployPlaygroundEnv = null;
|
|
174
148
|
}
|
|
175
149
|
}, SETUP_PLAYGROUND_ENV_TIMEOUT);
|
|
176
150
|
}
|
|
@@ -178,82 +152,106 @@ export function setupPlaygroundEnvironment(options = {}) {
|
|
|
178
152
|
* Creates a dev server instance using the shared playground environment.
|
|
179
153
|
* Automatically registers cleanup to run after the test.
|
|
180
154
|
*/
|
|
181
|
-
export
|
|
182
|
-
|
|
183
|
-
|
|
155
|
+
export function createDevServer() {
|
|
156
|
+
ensureHooksRegistered();
|
|
157
|
+
if (!globalDevPlaygroundEnv) {
|
|
158
|
+
throw new Error("Dev playground environment not initialized. Enable `dev: true` in setupPlaygroundEnvironment.");
|
|
184
159
|
}
|
|
160
|
+
const { projectDir } = globalDevPlaygroundEnv;
|
|
185
161
|
const packageManager = process.env.PACKAGE_MANAGER || "pnpm";
|
|
186
|
-
|
|
187
|
-
timeout: DEV_SERVER_TIMEOUT,
|
|
188
|
-
minTries: DEV_SERVER_MIN_TRIES,
|
|
189
|
-
onRetry: (error, tries) => {
|
|
190
|
-
console.log(`Retrying dev server creation (attempt ${tries})... Error: ${error.message}`);
|
|
191
|
-
},
|
|
192
|
-
});
|
|
162
|
+
let instance = null;
|
|
193
163
|
return {
|
|
194
|
-
|
|
195
|
-
|
|
164
|
+
projectDir,
|
|
165
|
+
start: async () => {
|
|
166
|
+
if (instance)
|
|
167
|
+
return instance;
|
|
168
|
+
if (SKIP_DEV_SERVER_TESTS) {
|
|
169
|
+
throw new Error("Dev server tests are skipped via RWSDK_SKIP_DEV=1");
|
|
170
|
+
}
|
|
171
|
+
const devResult = await pollValue(() => runDevServer(packageManager, projectDir), {
|
|
172
|
+
timeout: DEV_SERVER_TIMEOUT,
|
|
173
|
+
minTries: DEV_SERVER_MIN_TRIES,
|
|
174
|
+
onRetry: (error, tries) => {
|
|
175
|
+
console.log(`Retrying dev server creation (attempt ${tries})... Error: ${error.message}`);
|
|
176
|
+
},
|
|
177
|
+
});
|
|
178
|
+
instance = {
|
|
179
|
+
url: devResult.url,
|
|
180
|
+
projectDir,
|
|
181
|
+
stopDev: devResult.stopDev,
|
|
182
|
+
};
|
|
183
|
+
devInstances.push(instance);
|
|
184
|
+
return instance;
|
|
185
|
+
},
|
|
196
186
|
};
|
|
197
187
|
}
|
|
198
188
|
/**
|
|
199
189
|
* Creates a deployment instance using the shared playground environment.
|
|
200
190
|
* Automatically registers cleanup to run after the test.
|
|
201
191
|
*/
|
|
202
|
-
export
|
|
203
|
-
|
|
204
|
-
|
|
192
|
+
export function createDeployment() {
|
|
193
|
+
ensureHooksRegistered();
|
|
194
|
+
if (!globalDeployPlaygroundEnv) {
|
|
195
|
+
throw new Error("Deploy playground environment not initialized. Enable `deploy: true` in setupPlaygroundEnvironment.");
|
|
205
196
|
}
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
// Poll the URL to ensure it's live before proceeding
|
|
216
|
-
await poll(async () => {
|
|
217
|
-
try {
|
|
218
|
-
const response = await fetch(deployResult.url);
|
|
219
|
-
// We consider any response (even 4xx or 5xx) as success,
|
|
220
|
-
// as it means the worker is routable.
|
|
221
|
-
return response.status > 0;
|
|
222
|
-
}
|
|
223
|
-
catch (e) {
|
|
224
|
-
return false;
|
|
197
|
+
const { projectDir } = globalDeployPlaygroundEnv;
|
|
198
|
+
let instance = null;
|
|
199
|
+
return {
|
|
200
|
+
projectDir,
|
|
201
|
+
start: async () => {
|
|
202
|
+
if (instance)
|
|
203
|
+
return instance;
|
|
204
|
+
if (SKIP_DEPLOYMENT_TESTS) {
|
|
205
|
+
throw new Error("Deployment tests are skipped via RWSDK_SKIP_DEPLOY=1");
|
|
225
206
|
}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
207
|
+
const newInstance = await pollValue(async () => {
|
|
208
|
+
const dirName = basename(projectDir);
|
|
209
|
+
const match = dirName.match(/-e2e-test-([a-f0-9]+)$/);
|
|
210
|
+
const resourceUniqueKey = match
|
|
211
|
+
? match[1]
|
|
212
|
+
: Math.random().toString(36).substring(2, 15);
|
|
213
|
+
const deployResult = await runRelease(projectDir, projectDir, resourceUniqueKey);
|
|
214
|
+
await poll(async () => {
|
|
215
|
+
try {
|
|
216
|
+
const response = await fetch(deployResult.url);
|
|
217
|
+
return response.status > 0;
|
|
218
|
+
}
|
|
219
|
+
catch (e) {
|
|
220
|
+
return false;
|
|
221
|
+
}
|
|
222
|
+
}, {
|
|
223
|
+
timeout: DEPLOYMENT_CHECK_TIMEOUT,
|
|
224
|
+
});
|
|
225
|
+
const cleanup = async () => {
|
|
226
|
+
const performCleanup = async () => {
|
|
227
|
+
if (isRelatedToTest(deployResult.workerName, resourceUniqueKey)) {
|
|
228
|
+
await deleteWorker(deployResult.workerName, projectDir, resourceUniqueKey);
|
|
229
|
+
}
|
|
230
|
+
await deleteD1Database(resourceUniqueKey, projectDir, resourceUniqueKey);
|
|
231
|
+
};
|
|
232
|
+
performCleanup().catch((error) => {
|
|
233
|
+
console.warn(`Warning: Background deployment cleanup failed: ${error.message}`);
|
|
234
|
+
});
|
|
235
|
+
return Promise.resolve();
|
|
236
|
+
};
|
|
237
|
+
return {
|
|
238
|
+
url: deployResult.url,
|
|
239
|
+
workerName: deployResult.workerName,
|
|
240
|
+
resourceUniqueKey,
|
|
241
|
+
projectDir: projectDir,
|
|
242
|
+
cleanup,
|
|
243
|
+
};
|
|
244
|
+
}, {
|
|
245
|
+
timeout: DEPLOYMENT_TIMEOUT,
|
|
246
|
+
minTries: DEPLOYMENT_MIN_TRIES,
|
|
247
|
+
onRetry: (error, tries) => {
|
|
248
|
+
console.log(`Retrying deployment creation (attempt ${tries})... Error: ${error.message}`);
|
|
249
|
+
},
|
|
240
250
|
});
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
return {
|
|
244
|
-
url: deployResult.url,
|
|
245
|
-
workerName: deployResult.workerName,
|
|
246
|
-
resourceUniqueKey,
|
|
247
|
-
projectDir: projectDir,
|
|
248
|
-
cleanup,
|
|
249
|
-
};
|
|
250
|
-
}, {
|
|
251
|
-
timeout: DEPLOYMENT_TIMEOUT,
|
|
252
|
-
minTries: DEPLOYMENT_MIN_TRIES,
|
|
253
|
-
onRetry: (error, tries) => {
|
|
254
|
-
console.log(`Retrying deployment creation (attempt ${tries})... Error: ${error.message}`);
|
|
251
|
+
deploymentInstances.push(newInstance);
|
|
252
|
+
return newInstance;
|
|
255
253
|
},
|
|
256
|
-
}
|
|
254
|
+
};
|
|
257
255
|
}
|
|
258
256
|
/**
|
|
259
257
|
* Executes a test function with a retry mechanism for specific error codes.
|
|
@@ -302,7 +300,7 @@ function createTestRunner(testFn, envType) {
|
|
|
302
300
|
return (name, testLogic) => {
|
|
303
301
|
if ((envType === "dev" && SKIP_DEV_SERVER_TESTS) ||
|
|
304
302
|
(envType === "deploy" && SKIP_DEPLOYMENT_TESTS)) {
|
|
305
|
-
test.skip(name
|
|
303
|
+
test.skip(`${name} (${envType})`, () => { });
|
|
306
304
|
return;
|
|
307
305
|
}
|
|
308
306
|
describe.concurrent(name, () => {
|
|
@@ -364,12 +362,86 @@ function createTestRunner(testFn, envType) {
|
|
|
364
362
|
browser: browser,
|
|
365
363
|
page: page,
|
|
366
364
|
url: instance.url,
|
|
365
|
+
projectDir: instance
|
|
366
|
+
.projectDir,
|
|
367
367
|
});
|
|
368
368
|
});
|
|
369
369
|
});
|
|
370
370
|
});
|
|
371
371
|
};
|
|
372
372
|
}
|
|
373
|
+
/**
|
|
374
|
+
* Creates a low-level test runner that provides utilities for creating
|
|
375
|
+
* tests that need to perform setup actions before the server starts.
|
|
376
|
+
*/
|
|
377
|
+
function createSDKTestRunner() {
|
|
378
|
+
const internalRunner = (testFn) => {
|
|
379
|
+
return (name, testLogic) => {
|
|
380
|
+
describe.concurrent(name, () => {
|
|
381
|
+
let page;
|
|
382
|
+
let browser;
|
|
383
|
+
beforeAll(async () => {
|
|
384
|
+
const tempDir = path.join(os.tmpdir(), "rwsdk-e2e-tests");
|
|
385
|
+
const wsEndpointFile = path.join(tempDir, "wsEndpoint");
|
|
386
|
+
try {
|
|
387
|
+
const wsEndpoint = await fs.readFile(wsEndpointFile, "utf-8");
|
|
388
|
+
browser = await puppeteer.connect({
|
|
389
|
+
browserWSEndpoint: wsEndpoint,
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
catch (error) {
|
|
393
|
+
console.warn("Failed to connect to existing browser instance. " +
|
|
394
|
+
"This might happen if you are running a single test file. " +
|
|
395
|
+
"Launching a new browser instance instead.");
|
|
396
|
+
browser = await launchBrowser();
|
|
397
|
+
}
|
|
398
|
+
}, SETUP_WAIT_TIMEOUT);
|
|
399
|
+
afterAll(async () => {
|
|
400
|
+
if (browser) {
|
|
401
|
+
await browser.disconnect();
|
|
402
|
+
}
|
|
403
|
+
});
|
|
404
|
+
beforeEach(async () => {
|
|
405
|
+
if (!globalDevPlaygroundEnv && !globalDeployPlaygroundEnv) {
|
|
406
|
+
throw new Error("Test environment not initialized. Call setupPlaygroundEnvironment() in your test file.");
|
|
407
|
+
}
|
|
408
|
+
page = await browser.newPage();
|
|
409
|
+
page.setDefaultTimeout(PUPPETEER_TIMEOUT);
|
|
410
|
+
}, SETUP_WAIT_TIMEOUT);
|
|
411
|
+
afterEach(async () => {
|
|
412
|
+
if (page) {
|
|
413
|
+
try {
|
|
414
|
+
await page.close();
|
|
415
|
+
}
|
|
416
|
+
catch (error) {
|
|
417
|
+
console.warn(`Suppressing error during page.close() in test "${name}":`, error);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
});
|
|
421
|
+
testFn(">", async () => {
|
|
422
|
+
if (!browser) {
|
|
423
|
+
throw new Error("Test environment not ready.");
|
|
424
|
+
}
|
|
425
|
+
await runTestWithRetries(name, async () => {
|
|
426
|
+
await testLogic({
|
|
427
|
+
browser: browser,
|
|
428
|
+
page: page,
|
|
429
|
+
projectDir: globalDevPlaygroundEnv?.projectDir ||
|
|
430
|
+
globalDeployPlaygroundEnv?.projectDir ||
|
|
431
|
+
"",
|
|
432
|
+
});
|
|
433
|
+
});
|
|
434
|
+
});
|
|
435
|
+
});
|
|
436
|
+
};
|
|
437
|
+
};
|
|
438
|
+
const main = internalRunner(test);
|
|
439
|
+
return Object.assign(main, {
|
|
440
|
+
only: internalRunner(test.only),
|
|
441
|
+
skip: test.skip,
|
|
442
|
+
});
|
|
443
|
+
}
|
|
444
|
+
export const testSDK = createSDKTestRunner();
|
|
373
445
|
/**
|
|
374
446
|
* High-level test wrapper for dev server tests.
|
|
375
447
|
* Automatically skips if RWSDK_SKIP_DEV=1
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import "./setWebpackRequire";
|
|
2
2
|
export { default as React } from "react";
|
|
3
3
|
export { ClientOnly } from "./ClientOnly.js";
|
|
4
|
+
export { initClientNavigation, navigate } from "./navigation.js";
|
|
4
5
|
import type { HydrationOptions, Transport } from "./types";
|
|
5
6
|
export declare const fetchTransport: Transport;
|
|
6
7
|
export declare const initClient: ({ transport, hydrateRootOptions, handleResponse, }?: {
|