rwsdk 0.1.26 → 0.2.0-alpha.0

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.
Files changed (41) hide show
  1. package/dist/lib/smokeTests/browser.d.mts +4 -2
  2. package/dist/lib/smokeTests/browser.mjs +159 -7
  3. package/dist/lib/smokeTests/codeUpdates.d.mts +1 -0
  4. package/dist/lib/smokeTests/codeUpdates.mjs +47 -0
  5. package/dist/lib/smokeTests/development.d.mts +1 -1
  6. package/dist/lib/smokeTests/development.mjs +10 -3
  7. package/dist/lib/smokeTests/environment.mjs +1 -14
  8. package/dist/lib/smokeTests/release.d.mts +1 -1
  9. package/dist/lib/smokeTests/release.mjs +3 -2
  10. package/dist/lib/smokeTests/reporting.mjs +30 -2
  11. package/dist/lib/smokeTests/runSmokeTests.mjs +2 -2
  12. package/dist/lib/smokeTests/state.d.mts +8 -0
  13. package/dist/lib/smokeTests/state.mjs +10 -0
  14. package/dist/lib/smokeTests/templates/SmokeTestClient.template.js +17 -2
  15. package/dist/lib/smokeTests/templates/smokeTestClientStyles.module.css.template.d.ts +1 -0
  16. package/dist/lib/smokeTests/templates/smokeTestClientStyles.module.css.template.js +9 -0
  17. package/dist/lib/smokeTests/templates/smokeTestUrlStyles.css.template.d.ts +1 -0
  18. package/dist/lib/smokeTests/templates/smokeTestUrlStyles.css.template.js +9 -0
  19. package/dist/lib/smokeTests/types.d.mts +1 -0
  20. package/dist/runtime/clientNavigation.d.ts +6 -3
  21. package/dist/runtime/clientNavigation.js +72 -8
  22. package/dist/runtime/entries/types/client.d.ts +5 -0
  23. package/dist/runtime/lib/manifest.d.ts +2 -0
  24. package/dist/runtime/lib/manifest.js +17 -0
  25. package/dist/runtime/lib/router.d.ts +1 -0
  26. package/dist/runtime/register/worker.js +17 -5
  27. package/dist/runtime/render/renderRscThenableToHtmlStream.d.ts +3 -3
  28. package/dist/runtime/render/renderRscThenableToHtmlStream.js +7 -3
  29. package/dist/runtime/render/stylesheets.d.ts +9 -0
  30. package/dist/runtime/render/stylesheets.js +45 -0
  31. package/dist/runtime/worker.js +1 -0
  32. package/dist/scripts/debug-sync.mjs +125 -13
  33. package/dist/scripts/ensure-deploy-env.mjs +2 -2
  34. package/dist/scripts/smoke-test.mjs +6 -0
  35. package/dist/vite/manifestPlugin.d.mts +4 -0
  36. package/dist/vite/manifestPlugin.mjs +151 -0
  37. package/dist/vite/redwoodPlugin.mjs +4 -0
  38. package/dist/vite/ssrBridgePlugin.mjs +17 -8
  39. package/dist/vite/transformJsxScriptTagsPlugin.mjs +74 -33
  40. package/dist/vite/transformJsxScriptTagsPlugin.test.mjs +43 -15
  41. package/package.json +1 -1
@@ -1,5 +1,7 @@
1
1
  import { SmokeTestOptions, SmokeTestResult } from "./types.mjs";
2
2
  import type { Page, Browser } from "puppeteer-core";
3
+ export declare function checkUrlStyles(page: Page, expectedColor: "red" | "green"): Promise<void>;
4
+ export declare function checkClientModuleStyles(page: Page, expectedColor: "blue" | "green"): Promise<void>;
3
5
  /**
4
6
  * Launch a browser instance
5
7
  */
@@ -11,14 +13,14 @@ export declare function getBrowserPath(testOptions?: SmokeTestOptions): Promise<
11
13
  /**
12
14
  * Check a URL by performing smoke tests and realtime upgrade
13
15
  */
14
- export declare function checkUrl(url: string, artifactDir: string, browserPath?: string, headless?: boolean, bail?: boolean, skipClient?: boolean, environment?: string, realtime?: boolean, targetDir?: string, skipHmr?: boolean): Promise<void>;
16
+ export declare function checkUrl(url: string, artifactDir: string, browserPath?: string, headless?: boolean, bail?: boolean, skipClient?: boolean, environment?: string, realtime?: boolean, targetDir?: string, skipHmr?: boolean, skipStyleTests?: boolean): Promise<void>;
15
17
  /**
16
18
  * Check smoke test status for a specific URL
17
19
  */
18
20
  export declare function checkUrlSmoke(page: Page, url: string, isRealtime: boolean, bail: boolean | undefined, skipClient: boolean | undefined, environment: string | undefined, timestampState: {
19
21
  initialServerValue: number;
20
22
  clientUpdatedValue: number | null;
21
- }, targetDir?: string, skipHmr?: boolean): Promise<void>;
23
+ }, targetDir?: string, skipHmr?: boolean, skipStyleTests?: boolean): Promise<void>;
22
24
  /**
23
25
  * Check server-side smoke test status
24
26
  */
@@ -11,6 +11,77 @@ import { $ } from "../$.mjs";
11
11
  import { fail } from "./utils.mjs";
12
12
  import { reportSmokeTestResult } from "./reporting.mjs";
13
13
  import { updateTestStatus } from "./state.mjs";
14
+ import * as fs from "fs/promises";
15
+ import { template as urlStylesTemplate } from "./templates/smokeTestUrlStyles.css.template";
16
+ import { template as clientStylesTemplate } from "./templates/smokeTestClientStyles.module.css.template";
17
+ export async function checkUrlStyles(page, expectedColor) {
18
+ const selector = '[data-testid="smoke-test-url-styles"]';
19
+ log(`Checking for element with selector: ${selector}`);
20
+ const element = await page.waitForSelector(selector);
21
+ if (!element) {
22
+ throw new Error(`URL styles element not found with selector: ${selector}`);
23
+ }
24
+ const expectedRgb = expectedColor === "red" ? "rgb(255, 0, 0)" : "rgb(0, 128, 0)";
25
+ log(`Waiting for URL styles to apply with expected color: ${expectedRgb}`);
26
+ try {
27
+ // Wait for the background color to match the expected value with a timeout
28
+ await page.waitForFunction((expectedRgb) => {
29
+ const element = document.querySelector('[data-testid="smoke-test-url-styles"]');
30
+ if (!element)
31
+ return false;
32
+ const backgroundColor = window.getComputedStyle(element).backgroundColor;
33
+ return backgroundColor === expectedRgb;
34
+ }, { timeout: 10000 }, // 10 second timeout
35
+ expectedRgb);
36
+ // Get the final background color for logging
37
+ const backgroundColor = await page.evaluate(() => window.getComputedStyle(document.querySelector('[data-testid="smoke-test-url-styles"]')).backgroundColor);
38
+ log(`URL-based stylesheet check passed: background color is ${backgroundColor}`);
39
+ }
40
+ catch (error) {
41
+ // Get the actual background color for better error reporting
42
+ const actualBackgroundColor = await page.evaluate(() => {
43
+ const element = document.querySelector('[data-testid="smoke-test-url-styles"]');
44
+ return element
45
+ ? window.getComputedStyle(element).backgroundColor
46
+ : "element not found";
47
+ });
48
+ throw new Error(`URL-based stylesheet check failed: expected background color ${expectedRgb}, but got ${actualBackgroundColor} (timeout after 10 seconds)`);
49
+ }
50
+ }
51
+ export async function checkClientModuleStyles(page, expectedColor) {
52
+ const selector = '[data-testid="smoke-test-client-styles"]';
53
+ log(`Checking for element with selector: ${selector}`);
54
+ const element = await page.waitForSelector(selector);
55
+ if (!element) {
56
+ throw new Error(`Client module styles element not found with selector: ${selector}`);
57
+ }
58
+ const expectedRgb = expectedColor === "blue" ? "rgb(0, 0, 255)" : "rgb(0, 128, 0)";
59
+ log(`Waiting for client module styles to apply with expected color: ${expectedRgb}`);
60
+ try {
61
+ // Wait for the background color to match the expected value with a timeout
62
+ await page.waitForFunction((expectedRgb) => {
63
+ const element = document.querySelector('[data-testid="smoke-test-client-styles"]');
64
+ if (!element)
65
+ return false;
66
+ const backgroundColor = window.getComputedStyle(element).backgroundColor;
67
+ return backgroundColor === expectedRgb;
68
+ }, { timeout: 10000 }, // 10 second timeout
69
+ expectedRgb);
70
+ // Get the final background color for logging
71
+ const backgroundColor = await page.evaluate(() => window.getComputedStyle(document.querySelector('[data-testid="smoke-test-client-styles"]')).backgroundColor);
72
+ log(`Client module stylesheet check passed: background color is ${backgroundColor}`);
73
+ }
74
+ catch (error) {
75
+ // Get the actual background color for better error reporting
76
+ const actualBackgroundColor = await page.evaluate(() => {
77
+ const element = document.querySelector('[data-testid="smoke-test-client-styles"]');
78
+ return element
79
+ ? window.getComputedStyle(element).backgroundColor
80
+ : "element not found";
81
+ });
82
+ throw new Error(`Client module stylesheet check failed: expected background color ${expectedRgb}, but got ${actualBackgroundColor} (timeout after 10 seconds)`);
83
+ }
84
+ }
14
85
  /**
15
86
  * Launch a browser instance
16
87
  */
@@ -113,7 +184,7 @@ export async function getBrowserPath(testOptions) {
113
184
  /**
114
185
  * Check a URL by performing smoke tests and realtime upgrade
115
186
  */
116
- export async function checkUrl(url, artifactDir, browserPath, headless = true, bail = false, skipClient = false, environment = "Development", realtime = false, targetDir, skipHmr = false) {
187
+ export async function checkUrl(url, artifactDir, browserPath, headless = true, bail = false, skipClient = false, environment = "Development", realtime = false, targetDir, skipHmr = false, skipStyleTests = false) {
117
188
  console.log(`🔍 Testing URL: ${url}`);
118
189
  log("Launching browser");
119
190
  let browser;
@@ -146,7 +217,7 @@ export async function checkUrl(url, artifactDir, browserPath, headless = true, b
146
217
  // Skip upgradeToRealtime and just run the realtime tests directly
147
218
  try {
148
219
  log("Performing realtime-only smoke test");
149
- await checkUrlSmoke(page, url, true, bail, skipClient, environment, timestampState, targetDir, skipHmr);
220
+ await realtimeOnlyFlow(page, url, artifactDir, bail, skipClient, environment, targetDir, skipHmr, skipStyleTests);
150
221
  // Take a screenshot of the realtime test
151
222
  await takeScreenshot(page, url, artifactDir, `${environment.toLowerCase()}-realtime-passed`);
152
223
  }
@@ -170,7 +241,7 @@ export async function checkUrl(url, artifactDir, browserPath, headless = true, b
170
241
  log("Performing initial smoke test");
171
242
  let initialTestStatus = "passed";
172
243
  try {
173
- await checkUrlSmoke(page, url, false, bail, skipClient, environment, timestampState, targetDir, skipHmr);
244
+ await checkUrlSmoke(page, url, false, bail, skipClient, environment, timestampState, targetDir, skipHmr, skipStyleTests);
174
245
  }
175
246
  catch (error) {
176
247
  hasFailures = true;
@@ -193,7 +264,7 @@ export async function checkUrl(url, artifactDir, browserPath, headless = true, b
193
264
  try {
194
265
  await upgradeToRealtime(page, environment, bail);
195
266
  log("Performing post-upgrade smoke test");
196
- await checkUrlSmoke(page, url, true, bail, skipClient, environment, timestampState, targetDir, skipHmr);
267
+ await checkUrlSmoke(page, url, true, bail, skipClient, environment, timestampState, targetDir, skipHmr, skipStyleTests);
197
268
  }
198
269
  catch (error) {
199
270
  hasFailures = true;
@@ -242,7 +313,7 @@ export async function checkUrl(url, artifactDir, browserPath, headless = true, b
242
313
  /**
243
314
  * Check smoke test status for a specific URL
244
315
  */
245
- export async function checkUrlSmoke(page, url, isRealtime, bail = false, skipClient = false, environment = "Development", timestampState, targetDir, skipHmr = false) {
316
+ export async function checkUrlSmoke(page, url, isRealtime, bail = false, skipClient = false, environment = "Development", timestampState, targetDir, skipHmr = false, skipStyleTests = false) {
246
317
  const phase = isRealtime ? "Post-upgrade" : "Initial";
247
318
  console.log(`🔍 Testing ${phase} smoke tests at ${url}`);
248
319
  // Parse the base URL and path to properly handle smoke test queries
@@ -271,6 +342,7 @@ export async function checkUrlSmoke(page, url, isRealtime, bail = false, skipCli
271
342
  let clientTestError = null;
272
343
  let serverRenderCheckError = null;
273
344
  let hmrTestError = null;
345
+ let stylesheetTestError = null;
274
346
  // Step 1: Run initial server-side smoke test to check the server state
275
347
  log("Running initial server-side smoke test");
276
348
  let initialServerResult;
@@ -324,6 +396,52 @@ export async function checkUrlSmoke(page, url, isRealtime, bail = false, skipCli
324
396
  }
325
397
  return;
326
398
  }
399
+ // Step 1.5: Run stylesheet checks
400
+ if (!skipStyleTests) {
401
+ const env = environment === "Development" ? "dev" : "production";
402
+ const urlStylesKey = isRealtime ? "realtimeUrlStyles" : "initialUrlStyles";
403
+ const clientModuleStylesKey = isRealtime
404
+ ? "realtimeClientModuleStyles"
405
+ : "initialClientModuleStyles";
406
+ try {
407
+ await checkUrlStyles(page, "red");
408
+ updateTestStatus(env, urlStylesKey, "PASSED");
409
+ log(`${phase} URL styles check passed`);
410
+ }
411
+ catch (error) {
412
+ hasFailures = true;
413
+ updateTestStatus(env, urlStylesKey, "FAILED");
414
+ stylesheetTestError =
415
+ error instanceof Error ? error : new Error(String(error));
416
+ log("Error during URL styles check: %O", error);
417
+ console.error(`❌ URL styles check failed: ${error instanceof Error ? error.message : String(error)}`);
418
+ if (bail) {
419
+ throw error;
420
+ }
421
+ }
422
+ try {
423
+ await checkClientModuleStyles(page, "blue");
424
+ updateTestStatus(env, clientModuleStylesKey, "PASSED");
425
+ log(`${phase} client module styles check passed`);
426
+ }
427
+ catch (error) {
428
+ hasFailures = true;
429
+ updateTestStatus(env, clientModuleStylesKey, "FAILED");
430
+ if (!stylesheetTestError) {
431
+ stylesheetTestError =
432
+ error instanceof Error ? error : new Error(String(error));
433
+ }
434
+ log("Error during client module styles check: %O", error);
435
+ console.error(`❌ Client module styles check failed: ${error instanceof Error ? error.message : String(error)}`);
436
+ if (bail) {
437
+ throw error;
438
+ }
439
+ }
440
+ }
441
+ else {
442
+ log("Skipping stylesheet checks as requested");
443
+ console.log("⏩ Skipping stylesheet checks as requested");
444
+ }
327
445
  // Step 2: Run client-side smoke test to update the server timestamp
328
446
  log("Running client-side smoke test");
329
447
  let clientResult;
@@ -387,6 +505,14 @@ export async function checkUrlSmoke(page, url, isRealtime, bail = false, skipCli
387
505
  // Test client component HMR if client tests aren't skipped
388
506
  if (!skipClient) {
389
507
  await testClientComponentHmr(page, targetDir, phase, environment, bail);
508
+ // Test style HMR if style tests aren't skipped
509
+ if (!skipStyleTests) {
510
+ await testStyleHMR(page, targetDir);
511
+ }
512
+ else {
513
+ log("Skipping style HMR test as requested");
514
+ console.log("⏩ Skipping style HMR test as requested");
515
+ }
390
516
  }
391
517
  }
392
518
  catch (error) {
@@ -432,6 +558,9 @@ export async function checkUrlSmoke(page, url, isRealtime, bail = false, skipCli
432
558
  if (hmrTestError) {
433
559
  errors.push(`HMR test: ${hmrTestError.message}`);
434
560
  }
561
+ if (stylesheetTestError) {
562
+ errors.push(`Stylesheet test: ${stylesheetTestError.message}`);
563
+ }
435
564
  throw new Error(`Multiple test failures: ${errors.join(", ")}`);
436
565
  }
437
566
  log("URL smoke test completed successfully");
@@ -761,7 +890,7 @@ export async function checkServerUp(baseUrl, customPath = "/", retries = RETRIES
761
890
  /**
762
891
  * Perform only the realtime upgrade and tests without doing initial checks
763
892
  */
764
- async function realtimeOnlyFlow(page, url, artifactDir, bail, skipClient, environment, targetDir, skipHmr = false) {
893
+ async function realtimeOnlyFlow(page, url, artifactDir, bail, skipClient, environment, targetDir, skipHmr = false, skipStyleTests = false) {
765
894
  let hasFailures = false;
766
895
  let realtimeError = null;
767
896
  // Create timestamp state for the realtime-only flow
@@ -771,7 +900,7 @@ async function realtimeOnlyFlow(page, url, artifactDir, bail, skipClient, enviro
771
900
  };
772
901
  try {
773
902
  log("Performing realtime-only smoke test");
774
- await checkUrlSmoke(page, url, true, bail, skipClient, environment, timestampState, targetDir, skipHmr);
903
+ await checkUrlSmoke(page, url, true, bail, skipClient, environment, timestampState, targetDir, skipHmr, skipStyleTests);
775
904
  // Take a screenshot of the realtime test
776
905
  await takeScreenshot(page, url, artifactDir, `${environment.toLowerCase()}-realtime-passed`);
777
906
  }
@@ -1039,3 +1168,26 @@ export async function testClientComponentHmr(page, targetDir, phase = "", enviro
1039
1168
  return false;
1040
1169
  }
1041
1170
  }
1171
+ async function testStyleHMR(page, targetDir) {
1172
+ log("Running style HMR tests");
1173
+ console.log("🎨 Testing style HMR...");
1174
+ // --- HMR Test for URL-based Stylesheet ---
1175
+ const urlStylePath = join(targetDir, "src", "app", "smokeTestUrlStyles.css");
1176
+ const updatedUrlStyle = urlStylesTemplate.replace("rgb(255, 0, 0)", "rgb(0, 128, 0)");
1177
+ await fs.writeFile(urlStylePath, updatedUrlStyle);
1178
+ // --- HMR Test for Client Module Stylesheet ---
1179
+ const clientStylePath = join(targetDir, "src", "app", "components", "smokeTestClientStyles.module.css");
1180
+ const updatedClientStyle = clientStylesTemplate.replace("rgb(0, 0, 255)", "rgb(0, 128, 0)");
1181
+ await fs.writeFile(clientStylePath, updatedClientStyle);
1182
+ // Allow time for HMR to kick in
1183
+ await new Promise((resolve) => setTimeout(resolve, 5000));
1184
+ // Check URL-based stylesheet HMR
1185
+ await checkUrlStyles(page, "green");
1186
+ // Check client-module stylesheet HMR
1187
+ await checkClientModuleStyles(page, "green");
1188
+ // Restore original styles
1189
+ await fs.writeFile(urlStylePath, urlStylesTemplate);
1190
+ await fs.writeFile(clientStylePath, clientStylesTemplate);
1191
+ log("Style HMR tests completed successfully");
1192
+ console.log("✅ Style HMR tests passed");
1193
+ }
@@ -2,6 +2,7 @@
2
2
  * Creates the smoke test components in the target project directory
3
3
  */
4
4
  export declare function createSmokeTestComponents(targetDir: string, skipClient?: boolean): Promise<void>;
5
+ export declare function createSmokeTestStylesheets(targetDir: string): Promise<void>;
5
6
  /**
6
7
  * Modifies the worker.tsx and wrangler.jsonc files to add realtime support
7
8
  */
@@ -4,6 +4,8 @@ import { log } from "./constants.mjs";
4
4
  import { getSmokeTestFunctionsTemplate } from "./templates/smokeTestFunctions.template";
5
5
  import { getSmokeTestTemplate } from "./templates/SmokeTest.template";
6
6
  import { getSmokeTestClientTemplate } from "./templates/SmokeTestClient.template";
7
+ import { template as smokeTestUrlStylesCssTemplate } from "./templates/smokeTestUrlStyles.css.template";
8
+ import { template as smokeTestClientStylesCssTemplate } from "./templates/smokeTestClientStyles.module.css.template";
7
9
  import MagicString from "magic-string";
8
10
  import { parse as parseJsonc } from "jsonc-parser";
9
11
  /**
@@ -28,6 +30,8 @@ export async function createSmokeTestComponents(targetDir, skipClient = false) {
28
30
  await fs.writeFile(smokeTestFunctionsPath, smokeTestFunctionsContent);
29
31
  log("Writing SmokeTest component file");
30
32
  await fs.writeFile(smokeTestPath, smokeTestContent);
33
+ // Create smoke test stylesheet files
34
+ await createSmokeTestStylesheets(targetDir);
31
35
  // Only create client component if not skipping client-side tests
32
36
  if (!skipClient) {
33
37
  // Create SmokeTestClient.tsx
@@ -49,10 +53,53 @@ export async function createSmokeTestComponents(targetDir, skipClient = false) {
49
53
  console.log(`- ${smokeTestPath}`);
50
54
  if (!skipClient) {
51
55
  console.log(`- ${join(componentsDir, "__SmokeTestClient.tsx")}`);
56
+ console.log(`- ${join(componentsDir, "smokeTestClientStyles.module.css")}`);
52
57
  }
53
58
  else {
54
59
  console.log("- Client component skipped (--skip-client was specified)");
55
60
  }
61
+ console.log(`- ${join(targetDir, "src", "app", "smokeTestUrlStyles.css")}`);
62
+ }
63
+ export async function createSmokeTestStylesheets(targetDir) {
64
+ log("Creating smoke test stylesheets in project...");
65
+ // Create directories if they don't exist
66
+ const componentsDir = join(targetDir, "src", "app", "components");
67
+ const appDir = join(targetDir, "src", "app");
68
+ await fs.mkdir(componentsDir, { recursive: true });
69
+ await fs.mkdir(appDir, { recursive: true });
70
+ // Create smoke_tests_client_styles.module.css
71
+ const clientStylesPath = join(componentsDir, "smokeTestClientStyles.module.css");
72
+ log("Creating smokeTestClientStyles.module.css at: %s", clientStylesPath);
73
+ await fs.writeFile(clientStylesPath, smokeTestClientStylesCssTemplate);
74
+ // Create smoke_tests_url_styles.css
75
+ const urlStylesPath = join(appDir, "smokeTestUrlStyles.css");
76
+ log("Creating smokeTestUrlStyles.css at: %s", urlStylesPath);
77
+ await fs.writeFile(urlStylesPath, smokeTestUrlStylesCssTemplate);
78
+ // Modify Document.tsx to include the URL stylesheet using CSS URL import
79
+ const documentPath = join(appDir, "Document.tsx");
80
+ log("Modifying Document.tsx to include URL stylesheet at: %s", documentPath);
81
+ try {
82
+ const documentContent = await fs.readFile(documentPath, "utf-8");
83
+ const s = new MagicString(documentContent);
84
+ // Add the CSS URL import at the top of the file
85
+ const importMatch = documentContent.match(/^(import\s+.*?;\s*\n)*/m);
86
+ const insertPosition = importMatch ? importMatch[0].length : 0;
87
+ s.appendLeft(insertPosition, 'import smokeTestUrlStyles from "./smokeTestUrlStyles.css?url";\n');
88
+ // Add the link tag in the head using the imported variable
89
+ const headTagEnd = documentContent.indexOf("</head>");
90
+ if (headTagEnd !== -1) {
91
+ s.appendLeft(headTagEnd, ' <link rel="stylesheet" href={smokeTestUrlStyles} />\n');
92
+ await fs.writeFile(documentPath, s.toString(), "utf-8");
93
+ log("Successfully modified Document.tsx with CSS URL import pattern");
94
+ }
95
+ else {
96
+ log("Could not find </head> tag in Document.tsx");
97
+ }
98
+ }
99
+ catch (e) {
100
+ log("Could not modify Document.tsx: %s", e);
101
+ }
102
+ log("Smoke test stylesheets created successfully");
56
103
  }
57
104
  /**
58
105
  * Modifies the worker.tsx and wrangler.jsonc files to add realtime support
@@ -8,4 +8,4 @@ export declare function runDevServer(cwd?: string): Promise<{
8
8
  /**
9
9
  * Runs tests against the development server
10
10
  */
11
- export declare function runDevTest(url: string, artifactDir: string, customPath?: string, browserPath?: string, headless?: boolean, bail?: boolean, skipClient?: boolean, realtime?: boolean, skipHmr?: boolean): Promise<void>;
11
+ export declare function runDevTest(url: string, artifactDir: string, customPath?: string, browserPath?: string, headless?: boolean, bail?: boolean, skipClient?: boolean, realtime?: boolean, skipHmr?: boolean, skipStyleTests?: boolean): Promise<void>;
@@ -1,7 +1,7 @@
1
1
  import { setTimeout } from "node:timers/promises";
2
2
  import { log, RETRIES } from "./constants.mjs";
3
3
  import { $ } from "../$.mjs";
4
- import { checkUrl, checkServerUp } from "./browser.mjs";
4
+ import { checkUrl, checkServerUp, launchBrowser } from "./browser.mjs";
5
5
  import { fail } from "./utils.mjs";
6
6
  import { state } from "./state.mjs";
7
7
  /**
@@ -172,9 +172,11 @@ export async function runDevServer(cwd) {
172
172
  /**
173
173
  * Runs tests against the development server
174
174
  */
175
- export async function runDevTest(url, artifactDir, customPath = "/", browserPath, headless = true, bail = false, skipClient = false, realtime = false, skipHmr = false) {
175
+ export async function runDevTest(url, artifactDir, customPath = "/", browserPath, headless = true, bail = false, skipClient = false, realtime = false, skipHmr = false, skipStyleTests = false) {
176
176
  log("Starting dev server test with path: %s", customPath || "/");
177
177
  console.log("🚀 Testing local development server");
178
+ const browser = await launchBrowser(browserPath, headless);
179
+ const page = await browser.newPage();
178
180
  try {
179
181
  // DRY: check both root and custom path
180
182
  await checkServerUp(url, customPath, RETRIES, bail);
@@ -187,10 +189,12 @@ export async function runDevTest(url, artifactDir, customPath = "/", browserPath
187
189
  : "/" + customPath);
188
190
  // Pass the target directory to checkUrl for HMR testing
189
191
  const targetDir = state.resources.targetDir;
192
+ await page.goto(testUrl, { waitUntil: "networkidle0" });
190
193
  await checkUrl(testUrl, artifactDir, browserPath, headless, bail, skipClient, "Development", // Add environment context parameter
191
194
  realtime, // Add realtime parameter
192
195
  targetDir, // Add target directory for HMR testing
193
- skipHmr);
196
+ skipHmr, // Add skip HMR option
197
+ skipStyleTests);
194
198
  log("Development server test completed successfully");
195
199
  }
196
200
  catch (error) {
@@ -206,4 +210,7 @@ export async function runDevTest(url, artifactDir, customPath = "/", browserPath
206
210
  // Make sure we throw the error so it's properly handled upstream
207
211
  throw error;
208
212
  }
213
+ finally {
214
+ await browser.close();
215
+ }
209
216
  }
@@ -145,19 +145,6 @@ async function installDependencies(targetDir) {
145
145
  catch (error) {
146
146
  log("ERROR: Failed to install dependencies: %O", error);
147
147
  console.error(`❌ Failed to install dependencies: ${error instanceof Error ? error.message : String(error)}`);
148
- // Try npm as fallback if pnpm fails
149
- try {
150
- console.log("⚠️ pnpm install failed, trying npm install as fallback...");
151
- await $({
152
- cwd: targetDir,
153
- stdio: "pipe",
154
- }) `npm install`;
155
- console.log("✅ Dependencies installed successfully with npm");
156
- }
157
- catch (npmError) {
158
- log("ERROR: Both pnpm and npm install failed: %O", npmError);
159
- console.error(`❌ Failed to install dependencies with npm: ${npmError instanceof Error ? npmError.message : String(npmError)}`);
160
- throw new Error(`Failed to install project dependencies. Please ensure the project can be installed with pnpm or npm.`);
161
- }
148
+ throw new Error(`Failed to install project dependencies. Please ensure the project can be installed with pnpm.`);
162
149
  }
163
150
  }
@@ -40,7 +40,7 @@ export declare function runRelease(cwd: string, projectDir: string, resourceUniq
40
40
  /**
41
41
  * Runs tests against the production deployment
42
42
  */
43
- export declare function runReleaseTest(customPath: string | undefined, artifactDir: string, resources: TestResources, browserPath?: string, headless?: boolean, bail?: boolean, skipClient?: boolean, projectDir?: string, realtime?: boolean, skipHmr?: boolean): Promise<void>;
43
+ export declare function runReleaseTest(customPath: string | undefined, artifactDir: string, resources: TestResources, browserPath?: string, headless?: boolean, bail?: boolean, skipClient?: boolean, projectDir?: string, realtime?: boolean, skipHmr?: boolean, skipStyleTests?: boolean): Promise<void>;
44
44
  /**
45
45
  * Check if a resource name includes a specific resource unique key
46
46
  * This is used to identify resources created during our tests
@@ -379,7 +379,7 @@ export async function runRelease(cwd, projectDir, resourceUniqueKey) {
379
379
  /**
380
380
  * Runs tests against the production deployment
381
381
  */
382
- export async function runReleaseTest(customPath = "/", artifactDir, resources, browserPath, headless = true, bail = false, skipClient = false, projectDir, realtime = false, skipHmr = false) {
382
+ export async function runReleaseTest(customPath = "/", artifactDir, resources, browserPath, headless = true, bail = false, skipClient = false, projectDir, realtime = false, skipHmr = false, skipStyleTests = false) {
383
383
  log("Starting release test with path: %s", customPath || "/");
384
384
  console.log("\n🚀 Testing production deployment");
385
385
  try {
@@ -398,7 +398,8 @@ export async function runReleaseTest(customPath = "/", artifactDir, resources, b
398
398
  ? customPath
399
399
  : "/" + customPath);
400
400
  await checkUrl(testUrl, artifactDir, browserPath, headless, bail, skipClient, "Production", realtime, resources.targetDir, // Add target directory parameter
401
- true);
401
+ true, // Always skip HMR in production
402
+ skipStyleTests);
402
403
  log("Release test completed successfully");
403
404
  // Store the worker name if we didn't set it earlier
404
405
  if (resources && !resources.workerName) {
@@ -109,6 +109,8 @@ export async function generateFinalReport() {
109
109
  console.log(` │ ├─ Server-side: ${formatTestStatus(state.testStatus.dev.initialServerSide)}`);
110
110
  console.log(` │ ├─ Client-side: ${formatTestStatus(state.testStatus.dev.initialClientSide)}`);
111
111
  console.log(` │ ├─ Server Render Check: ${formatTestStatus(state.testStatus.dev.initialServerRenderCheck)}`);
112
+ console.log(` │ ├─ URL Styles: ${formatTestStatus(state.testStatus.dev.initialUrlStyles)}`);
113
+ console.log(` │ ├─ Client Module Styles: ${formatTestStatus(state.testStatus.dev.initialClientModuleStyles)}`);
112
114
  console.log(` │ ├─ Server HMR: ${formatTestStatus(state.testStatus.dev.initialServerHmr)}`);
113
115
  console.log(` │ └─ Client HMR: ${formatTestStatus(state.testStatus.dev.initialClientHmr)}`);
114
116
  console.log(` └─ Realtime Tests:`);
@@ -116,6 +118,8 @@ export async function generateFinalReport() {
116
118
  console.log(` ├─ Server-side: ${formatTestStatus(state.testStatus.dev.realtimeServerSide)}`);
117
119
  console.log(` ├─ Client-side: ${formatTestStatus(state.testStatus.dev.realtimeClientSide)}`);
118
120
  console.log(` ├─ Server Render Check: ${formatTestStatus(state.testStatus.dev.realtimeServerRenderCheck)}`);
121
+ console.log(` ├─ URL Styles: ${formatTestStatus(state.testStatus.dev.realtimeUrlStyles)}`);
122
+ console.log(` ├─ Client Module Styles: ${formatTestStatus(state.testStatus.dev.realtimeClientModuleStyles)}`);
119
123
  console.log(` ├─ Server HMR: ${formatTestStatus(state.testStatus.dev.realtimeServerHmr)}`);
120
124
  console.log(` └─ Client HMR: ${formatTestStatus(state.testStatus.dev.realtimeClientHmr)}`);
121
125
  }
@@ -130,12 +134,16 @@ export async function generateFinalReport() {
130
134
  console.log(` ├─ Initial Tests:`);
131
135
  console.log(` │ ├─ Server-side: ${formatTestStatus(state.testStatus.production.initialServerSide)}`);
132
136
  console.log(` │ ├─ Client-side: ${formatTestStatus(state.testStatus.production.initialClientSide)}`);
133
- console.log(` │ └─ Server Render Check: ${formatTestStatus(state.testStatus.production.initialServerRenderCheck)}`);
137
+ console.log(` │ ├─ Server Render Check: ${formatTestStatus(state.testStatus.production.initialServerRenderCheck)}`);
138
+ console.log(` │ ├─ URL Styles: ${formatTestStatus(state.testStatus.production.initialUrlStyles)}`);
139
+ console.log(` │ └─ Client Module Styles: ${formatTestStatus(state.testStatus.production.initialClientModuleStyles)}`);
134
140
  console.log(` └─ Realtime Tests:`);
135
141
  console.log(` ├─ Upgrade: ${formatTestStatus(state.testStatus.production.realtimeUpgrade)}`);
136
142
  console.log(` ├─ Server-side: ${formatTestStatus(state.testStatus.production.realtimeServerSide)}`);
137
143
  console.log(` ├─ Client-side: ${formatTestStatus(state.testStatus.production.realtimeClientSide)}`);
138
- console.log(` └─ Server Render Check: ${formatTestStatus(state.testStatus.production.realtimeServerRenderCheck)}`);
144
+ console.log(` ├─ Server Render Check: ${formatTestStatus(state.testStatus.production.realtimeServerRenderCheck)}`);
145
+ console.log(` ├─ URL Styles: ${formatTestStatus(state.testStatus.production.realtimeUrlStyles)}`);
146
+ console.log(` └─ Client Module Styles: ${formatTestStatus(state.testStatus.production.realtimeClientModuleStyles)}`);
139
147
  }
140
148
  else {
141
149
  console.log(` └─ Tests: ⏩ SKIPPED (release command failed)`);
@@ -258,6 +266,10 @@ export function initializeTestStatus() {
258
266
  state.testStatus.dev.initialClientHmr = "DID_NOT_RUN";
259
267
  state.testStatus.dev.realtimeServerHmr = "DID_NOT_RUN";
260
268
  state.testStatus.dev.realtimeClientHmr = "DID_NOT_RUN";
269
+ state.testStatus.dev.initialUrlStyles = "DID_NOT_RUN";
270
+ state.testStatus.dev.initialClientModuleStyles = "DID_NOT_RUN";
271
+ state.testStatus.dev.realtimeUrlStyles = "DID_NOT_RUN";
272
+ state.testStatus.dev.realtimeClientModuleStyles = "DID_NOT_RUN";
261
273
  // Production tests
262
274
  state.testStatus.production.overall = "DID_NOT_RUN";
263
275
  state.testStatus.production.releaseCommand = "DID_NOT_RUN";
@@ -272,6 +284,10 @@ export function initializeTestStatus() {
272
284
  state.testStatus.production.initialClientHmr = "DID_NOT_RUN";
273
285
  state.testStatus.production.realtimeServerHmr = "DID_NOT_RUN";
274
286
  state.testStatus.production.realtimeClientHmr = "DID_NOT_RUN";
287
+ state.testStatus.production.initialUrlStyles = "DID_NOT_RUN";
288
+ state.testStatus.production.initialClientModuleStyles = "DID_NOT_RUN";
289
+ state.testStatus.production.realtimeUrlStyles = "DID_NOT_RUN";
290
+ state.testStatus.production.realtimeClientModuleStyles = "DID_NOT_RUN";
275
291
  // Now override with specific statuses based on options
276
292
  // Mark skipped tests based on options
277
293
  if (state.options.skipDev) {
@@ -287,6 +303,10 @@ export function initializeTestStatus() {
287
303
  state.testStatus.dev.initialClientHmr = "SKIPPED";
288
304
  state.testStatus.dev.realtimeServerHmr = "SKIPPED";
289
305
  state.testStatus.dev.realtimeClientHmr = "SKIPPED";
306
+ state.testStatus.dev.initialUrlStyles = "SKIPPED";
307
+ state.testStatus.dev.initialClientModuleStyles = "SKIPPED";
308
+ state.testStatus.dev.realtimeUrlStyles = "SKIPPED";
309
+ state.testStatus.dev.realtimeClientModuleStyles = "SKIPPED";
290
310
  }
291
311
  if (state.options.skipRelease) {
292
312
  state.testStatus.production.overall = "SKIPPED";
@@ -302,6 +322,10 @@ export function initializeTestStatus() {
302
322
  state.testStatus.production.initialClientHmr = "SKIPPED";
303
323
  state.testStatus.production.realtimeServerHmr = "SKIPPED";
304
324
  state.testStatus.production.realtimeClientHmr = "SKIPPED";
325
+ state.testStatus.production.initialUrlStyles = "SKIPPED";
326
+ state.testStatus.production.initialClientModuleStyles = "SKIPPED";
327
+ state.testStatus.production.realtimeUrlStyles = "SKIPPED";
328
+ state.testStatus.production.realtimeClientModuleStyles = "SKIPPED";
305
329
  }
306
330
  if (state.options.skipClient) {
307
331
  state.testStatus.dev.initialClientSide = "SKIPPED";
@@ -337,6 +361,8 @@ export function initializeTestStatus() {
337
361
  state.testStatus.dev.initialServerRenderCheck = "SKIPPED";
338
362
  state.testStatus.dev.initialServerHmr = "SKIPPED";
339
363
  state.testStatus.dev.initialClientHmr = "SKIPPED";
364
+ state.testStatus.dev.initialUrlStyles = "SKIPPED";
365
+ state.testStatus.dev.initialClientModuleStyles = "SKIPPED";
340
366
  // Set the upgrade test to PASSED as it's implicitly run for realtime mode
341
367
  state.testStatus.dev.realtimeUpgrade = "PASSED";
342
368
  }
@@ -346,6 +372,8 @@ export function initializeTestStatus() {
346
372
  state.testStatus.production.initialServerRenderCheck = "SKIPPED";
347
373
  state.testStatus.production.initialServerHmr = "SKIPPED";
348
374
  state.testStatus.production.initialClientHmr = "SKIPPED";
375
+ state.testStatus.production.initialUrlStyles = "SKIPPED";
376
+ state.testStatus.production.initialClientModuleStyles = "SKIPPED";
349
377
  // Set release command to PASSED since it must have succeeded for realtime tests to run
350
378
  state.testStatus.production.releaseCommand = "PASSED";
351
379
  // Set the upgrade test to PASSED as it's implicitly run for realtime mode
@@ -57,7 +57,7 @@ export async function runSmokeTests(options = {}) {
57
57
  resources.stopDev = stopDev;
58
58
  state.resources.stopDev = stopDev;
59
59
  log("Running development server tests");
60
- await runDevTest(url, options.artifactDir, options.customPath, browserPath, options.headless !== false, options.bail, options.skipClient, options.realtime, options.skipHmr);
60
+ await runDevTest(url, options.artifactDir, options.customPath, browserPath, options.headless !== false, options.bail, options.skipClient, options.realtime, options.skipHmr, options.skipStyleTests);
61
61
  // Mark that dev tests have run successfully
62
62
  state.devTestsRan = true;
63
63
  // Update the overall dev test status to PASSED
@@ -95,7 +95,7 @@ export async function runSmokeTests(options = {}) {
95
95
  // Update status when release command runs
96
96
  try {
97
97
  console.log("\n🚀 Running release command smoke test");
98
- await runReleaseTest(options.customPath, options.artifactDir, resources, browserPath, options.headless !== false, options.bail, options.skipClient, options.projectDir, options.realtime, options.skipHmr);
98
+ await runReleaseTest(options.customPath, options.artifactDir, resources, browserPath, options.headless !== false, options.bail, options.skipClient, options.projectDir, options.realtime, options.skipHmr, options.skipStyleTests);
99
99
  // Update release command status to PASSED
100
100
  updateTestStatus("production", "releaseCommand", "PASSED");
101
101
  // Mark that release tests have run successfully
@@ -14,6 +14,10 @@ export interface TestStatus {
14
14
  initialClientHmr: TestStatusValue;
15
15
  realtimeServerHmr: TestStatusValue;
16
16
  realtimeClientHmr: TestStatusValue;
17
+ initialUrlStyles: TestStatusValue;
18
+ initialClientModuleStyles: TestStatusValue;
19
+ realtimeUrlStyles: TestStatusValue;
20
+ realtimeClientModuleStyles: TestStatusValue;
17
21
  };
18
22
  production: {
19
23
  overall: TestStatusValue;
@@ -29,6 +33,10 @@ export interface TestStatus {
29
33
  initialClientHmr: TestStatusValue;
30
34
  realtimeServerHmr: TestStatusValue;
31
35
  realtimeClientHmr: TestStatusValue;
36
+ initialUrlStyles: TestStatusValue;
37
+ initialClientModuleStyles: TestStatusValue;
38
+ realtimeUrlStyles: TestStatusValue;
39
+ realtimeClientModuleStyles: TestStatusValue;
32
40
  };
33
41
  }
34
42
  export declare const state: {
@@ -32,6 +32,11 @@ export const state = {
32
32
  initialClientHmr: "DID_NOT_RUN",
33
33
  realtimeServerHmr: "DID_NOT_RUN",
34
34
  realtimeClientHmr: "DID_NOT_RUN",
35
+ // Style check statuses
36
+ initialUrlStyles: "DID_NOT_RUN",
37
+ initialClientModuleStyles: "DID_NOT_RUN",
38
+ realtimeUrlStyles: "DID_NOT_RUN",
39
+ realtimeClientModuleStyles: "DID_NOT_RUN",
35
40
  },
36
41
  production: {
37
42
  overall: "DID_NOT_RUN",
@@ -48,6 +53,11 @@ export const state = {
48
53
  initialClientHmr: "DID_NOT_RUN",
49
54
  realtimeServerHmr: "DID_NOT_RUN",
50
55
  realtimeClientHmr: "DID_NOT_RUN",
56
+ // Style check statuses
57
+ initialUrlStyles: "DID_NOT_RUN",
58
+ initialClientModuleStyles: "DID_NOT_RUN",
59
+ realtimeUrlStyles: "DID_NOT_RUN",
60
+ realtimeClientModuleStyles: "DID_NOT_RUN",
51
61
  },
52
62
  },
53
63
  };