tangled
alpha
login
or
join now
erika.florist
/
maudit
6
fork
atom
Rust library to generate static websites
6
fork
atom
overview
issues
pulls
1
pipelines
fix: e2e tests
Princesseuh
1 month ago
f6141d36
f6e55dd0
+119
-6
2 changed files
expand all
collapse all
unified
split
e2e
tests
hot-reload.spec.ts
test-utils.ts
+95
-5
e2e/tests/hot-reload.spec.ts
···
15
15
test.describe("Hot Reload", () => {
16
16
const fixturePath = resolve(__dirname, "..", "fixtures", "hot-reload");
17
17
const indexPath = resolve(fixturePath, "src", "pages", "index.rs");
18
18
-
let originalContent: string;
18
18
+
const mainPath = resolve(fixturePath, "src", "main.rs");
19
19
+
let originalIndexContent: string;
20
20
+
let originalMainContent: string;
19
21
20
22
test.beforeAll(async () => {
21
23
// Save original content
22
22
-
originalContent = readFileSync(indexPath, "utf-8");
24
24
+
originalIndexContent = readFileSync(indexPath, "utf-8");
25
25
+
originalMainContent = readFileSync(mainPath, "utf-8");
23
26
});
24
27
25
28
test.afterEach(async () => {
26
29
// Restore original content after each test
27
27
-
writeFileSync(indexPath, originalContent, "utf-8");
30
30
+
writeFileSync(indexPath, originalIndexContent, "utf-8");
31
31
+
writeFileSync(mainPath, originalMainContent, "utf-8");
28
32
// Wait a bit for the rebuild
29
33
await new Promise((resolve) => setTimeout(resolve, 2000));
30
34
});
31
35
32
36
test.afterAll(async () => {
33
37
// Restore original content
34
34
-
writeFileSync(indexPath, originalContent, "utf-8");
38
38
+
writeFileSync(indexPath, originalIndexContent, "utf-8");
39
39
+
writeFileSync(mainPath, originalMainContent, "utf-8");
40
40
+
});
41
41
+
42
42
+
test("should recompile when Rust code changes (dependencies)", async ({ page, devServer }) => {
43
43
+
await page.goto(devServer.url);
44
44
+
45
45
+
// Verify initial content
46
46
+
await expect(page.locator("#title")).toHaveText("Original Title");
47
47
+
48
48
+
// Clear logs to track what happens after this point
49
49
+
devServer.clearLogs();
50
50
+
51
51
+
// Modify main.rs - this is a tracked dependency, should trigger recompile
52
52
+
const modifiedMain = originalMainContent.replace(
53
53
+
"BuildOptions::default()",
54
54
+
"BuildOptions::default() // Modified comment",
55
55
+
);
56
56
+
writeFileSync(mainPath, modifiedMain, "utf-8");
57
57
+
58
58
+
// Wait for rebuild to complete - look for "finished" in logs
59
59
+
await new Promise((resolve) => {
60
60
+
const checkInterval = setInterval(() => {
61
61
+
const logs = devServer.getLogs(50).join("\n");
62
62
+
if (logs.includes("finished") || logs.includes("Rebuild")) {
63
63
+
clearInterval(checkInterval);
64
64
+
resolve(null);
65
65
+
}
66
66
+
}, 100);
67
67
+
68
68
+
// Timeout after 15 seconds
69
69
+
setTimeout(() => {
70
70
+
clearInterval(checkInterval);
71
71
+
resolve(null);
72
72
+
}, 15000);
73
73
+
});
74
74
+
75
75
+
// Check logs to verify it actually recompiled (ran cargo)
76
76
+
const logs = devServer.getLogs(50).join("\n");
77
77
+
expect(logs).toContain("rebuilding");
78
78
+
expect(logs).not.toContain("Rerunning binary");
79
79
+
expect(logs).not.toContain("rerunning binary");
80
80
+
});
81
81
+
82
82
+
test("should rerun without recompile when template changes (non-dependencies)", async ({
83
83
+
page,
84
84
+
devServer
85
85
+
}) => {
86
86
+
await page.goto(devServer.url);
87
87
+
88
88
+
// Verify initial content
89
89
+
await expect(page.locator("#title")).toHaveText("Original Title");
90
90
+
91
91
+
// Prepare to wait for actual reload
92
92
+
const currentUrl = page.url();
93
93
+
94
94
+
// Clear logs to track what happens after this point
95
95
+
devServer.clearLogs();
96
96
+
97
97
+
// Modify the template in index.rs - this should NOT require recompilation
98
98
+
// since it's just the HTML template, not the actual Rust code structure
99
99
+
const modifiedContent = originalIndexContent.replace(
100
100
+
'h1 id="title" { "Original Title" }',
101
101
+
'h1 id="title" { "Template Updated" }',
102
102
+
);
103
103
+
writeFileSync(indexPath, modifiedContent, "utf-8");
104
104
+
105
105
+
// Wait for the page to reload
106
106
+
await page.waitForURL(currentUrl, { timeout: 15000 });
107
107
+
108
108
+
// Verify the updated content
109
109
+
await expect(page.locator("#title")).toHaveText("Template Updated", { timeout: 15000 });
110
110
+
111
111
+
// Give logs time to be captured
112
112
+
await new Promise((resolve) => setTimeout(resolve, 1000));
113
113
+
114
114
+
// Check logs to verify it did NOT recompile
115
115
+
const logs = devServer.getLogs(50).join("\n");
116
116
+
117
117
+
// Should see "rerunning binary" or similar message
118
118
+
const hasRerunMessage = logs.toLowerCase().includes("rerunning") ||
119
119
+
logs.toLowerCase().includes("rerun");
120
120
+
expect(hasRerunMessage).toBe(true);
121
121
+
122
122
+
// Should NOT see cargo compilation messages
123
123
+
expect(logs).not.toContain("Compiling");
124
124
+
expect(logs.toLowerCase()).not.toContain("rebuilding");
35
125
});
36
126
37
127
test("should show updated content after file changes", async ({ page, devServer }) => {
···
44
134
const currentUrl = page.url();
45
135
46
136
// Modify the file
47
47
-
const modifiedContent = originalContent.replace(
137
137
+
const modifiedContent = originalIndexContent.replace(
48
138
'h1 id="title" { "Original Title" }',
49
139
'h1 id="title" { "Another Update" }',
50
140
);
+24
-1
e2e/tests/test-utils.ts
···
23
23
port: number;
24
24
/** Stop the dev server */
25
25
stop: () => Promise<void>;
26
26
+
/** Get recent log output (last N lines) */
27
27
+
getLogs: (lines?: number) => string[];
28
28
+
/** Clear captured logs */
29
29
+
clearLogs: () => void;
26
30
}
27
31
28
32
/**
···
56
60
57
61
// Capture output to detect when server is ready
58
62
let serverReady = false;
63
63
+
const capturedLogs: string[] = [];
59
64
60
65
const outputPromise = new Promise<number>((resolve, reject) => {
61
66
const timeout = setTimeout(() => {
···
64
69
65
70
childProcess.stdout?.on("data", (data: Buffer) => {
66
71
const output = data.toString();
72
72
+
// Capture all stdout logs
73
73
+
output.split("\n").filter(line => line.trim()).forEach(line => {
74
74
+
capturedLogs.push(line);
75
75
+
});
67
76
68
77
// Look for "waiting for requests" to know server is ready
69
78
if (output.includes("waiting for requests")) {
···
75
84
});
76
85
77
86
childProcess.stderr?.on("data", (data: Buffer) => {
78
78
-
// Only log errors, not all stderr output
79
87
const output = data.toString();
88
88
+
// Capture all stderr logs
89
89
+
output.split("\n").filter(line => line.trim()).forEach(line => {
90
90
+
capturedLogs.push(line);
91
91
+
});
92
92
+
93
93
+
// Only log errors to console, not all stderr output
80
94
if (output.toLowerCase().includes("error")) {
81
95
console.error(`[maudit dev] ${output}`);
82
96
}
···
112
126
}
113
127
}, 5000);
114
128
});
129
129
+
},
130
130
+
getLogs: (lines?: number) => {
131
131
+
if (lines) {
132
132
+
return capturedLogs.slice(-lines);
133
133
+
}
134
134
+
return [...capturedLogs];
135
135
+
},
136
136
+
clearLogs: () => {
137
137
+
capturedLogs.length = 0;
115
138
},
116
139
};
117
140
}