forked from dwgx/WindsurfAPI
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdashboard-syntax.test.js
More file actions
141 lines (122 loc) · 6.83 KB
/
Copy pathdashboard-syntax.test.js
File metadata and controls
141 lines (122 loc) · 6.83 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
import test from 'node:test';
import assert from 'node:assert/strict';
import { readFileSync } from 'fs';
import { dirname, join } from 'path';
import { fileURLToPath } from 'url';
const __dirname = dirname(fileURLToPath(import.meta.url));
const root = join(__dirname, '..');
for (const skin of ['src/dashboard/index.html', 'src/dashboard/index-sketch.html']) {
test(`${skin} inline scripts are syntactically valid`, () => {
const html = readFileSync(join(root, skin), 'utf8');
const scripts = [...html.matchAll(/<script([^>]*)>([\s\S]*?)<\/script>/gi)]
.map((match, index) => ({ index, attrs: match[1] || '', source: match[2] || '' }))
.filter(({ attrs }) => !/\bsrc\s*=/.test(attrs))
.filter(({ attrs }) => !/\btype\s*=\s*["']module["']/i.test(attrs));
assert.ok(scripts.length > 0, `expected at least one non-module inline script in ${skin}`);
for (const { index, source } of scripts) {
assert.doesNotThrow(() => new Function(source), `inline script #${index} in ${skin} should parse`);
}
});
}
test('docs/index.html inline scripts are syntactically valid', () => {
const html = readFileSync(join(root, 'docs/index.html'), 'utf8');
const scripts = [...html.matchAll(/<script([^>]*)>([\s\S]*?)<\/script>/gi)]
.map((match, index) => ({ index, attrs: match[1] || '', source: match[2] || '' }))
.filter(({ attrs }) => !/\bsrc\s*=/.test(attrs))
.filter(({ attrs }) => !/\btype\s*=\s*["']module["']/i.test(attrs));
assert.ok(scripts.length > 0, 'expected at least one non-module inline script in docs/index.html');
for (const { index, source } of scripts) {
assert.doesNotThrow(() => new Function(source), `inline script #${index} in docs/index.html should parse`);
}
});
test('dashboard system prompt editor escapes prompt keys before rendering or routing', () => {
const html = readFileSync(join(root, 'src/dashboard/index.html'), 'utf8');
assert.match(html, /const safeKey = this\.esc\(key\)/);
assert.match(html, /const keyArg = this\.escJsAttr\(key\)/);
assert.match(html, /this\.systemPromptDomId\(key\)/);
assert.match(html, /encodeURIComponent\(key\)/);
assert.doesNotMatch(html, /\$\{key\}<\/code>/);
assert.doesNotMatch(html, /resetSystemPrompt\('\$\{key\}'\)/);
});
test('dashboard batch login history uses each result proxy instead of an undefined local', () => {
const html = readFileSync(join(root, 'src/dashboard/index.html'), 'utf8');
assert.match(html, /proxy:\s*this\.getWindsurfProxyLabel\(item\.proxy\)/);
assert.doesNotMatch(html, /proxy:\s*this\.getWindsurfProxyLabel\(proxy\),\s*\r?\n\s*status:\s*item\.success/);
});
test('dashboard proxy and abnormal-account tables use paged account summaries', () => {
const html = readFileSync(join(root, 'src/dashboard/index.html'), 'utf8');
assert.match(html, /id="proxy-accounts-pagination"/);
assert.match(html, /id="ban-pagination"/);
assert.match(html, /setProxyPage\(page\)/);
assert.match(html, /setBansPage\(page\)/);
assert.match(html, /this\.accountsListUrl\(\{\s*page:\s*this\.proxyPage,\s*pageSize:\s*this\.proxyPageSize/s);
assert.match(html, /filter:\s*'flagged'/);
assert.doesNotMatch(html, /pageSize=1000/);
assert.doesNotMatch(html, /pageSize=500/);
});
test('dashboard sketch proxy and abnormal-account tables use lightweight summaries', () => {
const html = readFileSync(join(root, 'src/dashboard/index-sketch.html'), 'utf8');
assert.match(html, /\/accounts\?view=summary&pageSize=200/);
assert.match(html, /\/accounts\?view=summary&filter=flagged&pageSize=200/);
assert.doesNotMatch(html, /pageSize=1000/);
assert.doesNotMatch(html, /pageSize=500/);
});
test('dashboard Quick Login uses the Windsurf sign-in + token flow (no dead Firebase popup)', () => {
const html = readFileSync(join(root, 'src/dashboard/index.html'), 'utf8');
const sketch = readFileSync(join(root, 'src/dashboard/index-sketch.html'), 'utf8');
// index-sketch still uses the Firebase signInWithPopup flow, so it must detect the
// origin-block (unauthorized-domain / referer-blocked) and steer users to the token
// fallback rather than leaving them stuck.
assert.match(sketch, /isFirebaseOAuthOriginBlocked/);
assert.match(sketch, /requests-from-referer-\.\*are-blocked/);
assert.match(sketch, /unauthorized-domain/);
// Both variants surface the windsurf.com token path.
for (const source of [html, sketch]) {
assert.match(source, /windsurf\.com\/show-auth-token/);
}
// index.html's Quick Login no longer relies on Firebase signInWithPopup — it is
// permanently origin-blocked on a self-hosted public origin. It now drives the
// Windsurf official sign-in + paste-token flow unconditionally (App.oauthLogin →
// buildWindsurfSigninUrl → App.submitOAuthToken).
assert.match(html, /windsurf\.com\/windsurf\/signin/);
assert.match(html, /submitOAuthToken/);
// The Firebase Auth SDK (which provided signInWithPopup) must no longer be imported.
assert.doesNotMatch(html, /firebasejs\/[\d.]+\/firebase-auth/);
});
test('recent merged PR contributors are represented in dashboard and README credits', () => {
const contributorData = JSON.parse(readFileSync(join(root, 'src/dashboard/data/contributors.json'), 'utf8'));
const readme = readFileSync(join(root, 'README.md'), 'utf8');
const readmeEn = readFileSync(join(root, 'README.en.md'), 'utf8');
const required = [
{ login: 'MatrixNeoKozak', pr: 195 },
{ login: 'brandonedley', pr: 201 },
];
for (const { login, pr } of required) {
assert.ok(
contributorData.contributors.some(entry => entry.login === login && entry.pr === pr),
`contributors.json should include @${login} PR #${pr}`,
);
assert.match(readme, new RegExp(`@${login}[\\s\\S]*PR #${pr}`));
assert.match(readmeEn, new RegExp(`@${login}[\\s\\S]*PR #${pr}`));
}
});
test('docs homepage renders contributors from the published dashboard JSON', () => {
const html = readFileSync(join(root, 'docs/index.html'), 'utf8');
const contributorsSection = html.slice(
html.indexOf('<section class="contributors-section"'),
html.indexOf('<!-- ── Footer ── -->'),
);
assert.match(html, /id="contributors-grid" data-source="dashboard\/data\/contributors\.json"/);
assert.match(html, /fetch\(source,\{cache:'no-cache'\}\)/);
assert.match(html, /function renderContributors\(entries\)/);
assert.match(html, /id="contributors-footer"/);
assert.doesNotMatch(contributorsSection, /href="https:\/\/github\.com\/aict666"/);
assert.doesNotMatch(contributorsSection, /PR #192/);
});
test('docs contributor JSON mirrors the canonical dashboard contributor data', () => {
const source = readFileSync(join(root, 'src/dashboard/data/contributors.json'), 'utf8');
const published = readFileSync(join(root, 'docs/dashboard/data/contributors.json'), 'utf8');
const parsed = JSON.parse(published);
assert.deepEqual(JSON.parse(source), parsed);
assert.equal(published, source);
});