mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-10-23 08:55:44 +08:00
Merge pull request #2699 from langbot-app/test/quality-account-ui-oracles-20261017
test(web): replace account and privacy source checks with browser behavior
This commit is contained in:
@@ -1,19 +0,0 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import fs from 'node:fs';
|
||||
import test from 'node:test';
|
||||
|
||||
const source = fs.readFileSync(
|
||||
new URL('../../src/app/login/page.tsx', import.meta.url),
|
||||
'utf8',
|
||||
);
|
||||
|
||||
test('normal Cloud login uses the standard Space OAuth callback path', () => {
|
||||
assert.doesNotMatch(source, /cloudEntry/);
|
||||
assert.match(source, /getSpaceAuthorizeUrl\(redirectUri\)/);
|
||||
});
|
||||
|
||||
test('invitation login uses the same OAuth callback before accepting the invitation', () => {
|
||||
assert.doesNotMatch(source, /cloudEntry/);
|
||||
assert.match(source, /const invitationToken = getPendingInvitationToken\(\)/);
|
||||
assert.match(source, /acceptWorkspaceInvitation\(invitationToken\)/);
|
||||
});
|
||||
@@ -10,45 +10,6 @@ const root = path.resolve(
|
||||
);
|
||||
const read = (file) => fs.readFileSync(path.join(root, file), 'utf8');
|
||||
|
||||
test('invited local registration returns to login instead of authenticating', () => {
|
||||
const source = read('src/app/invitations/accept/page.tsx');
|
||||
assert.doesNotMatch(
|
||||
source,
|
||||
/beginAuthenticatedSession\([\s\S]{0,120}response\.token/,
|
||||
);
|
||||
assert.match(source, /navigate\('\/login\?invitation=1'/);
|
||||
});
|
||||
|
||||
test('authenticated invitation page offers logout while retaining invitation', () => {
|
||||
const source = read('src/app/invitations/accept/page.tsx');
|
||||
assert.match(source, /workspace\.logoutAndReturn/);
|
||||
assert.match(source, /setPendingInvitationToken\(token\)/);
|
||||
});
|
||||
|
||||
test('Space OAuth callback distinguishes unknown and unbound accounts by stable codes', () => {
|
||||
const source = read('src/app/auth/space/callback/page.tsx');
|
||||
assert.match(source, /space_account_not_registered/);
|
||||
assert.match(source, /space_account_binding_required/);
|
||||
});
|
||||
|
||||
test('models panel derives LangBot Models billing state from workspace owner', () => {
|
||||
const source = read('src/app/home/components/models-dialog/ModelsPanel.tsx');
|
||||
assert.match(source, /getWorkspaceSpaceBilling/);
|
||||
assert.doesNotMatch(source, /getSpaceCredits\(\)/);
|
||||
assert.match(source, /membership\.role === 'owner'/);
|
||||
});
|
||||
|
||||
test('provider card represents owner and member owner-bound states explicitly', () => {
|
||||
const source = read(
|
||||
'src/app/home/components/models-dialog/components/ProviderCard.tsx',
|
||||
);
|
||||
assert.match(source, /isWorkspaceOwner/);
|
||||
assert.match(source, /ownerSpaceBound/);
|
||||
assert.match(source, /models\.ownerMustBindSpace/);
|
||||
assert.match(source, /models\.usesOwnerSpaceBilling/);
|
||||
assert.match(source, /isWorkspaceOwner && \(\s*<Button/);
|
||||
});
|
||||
|
||||
test('workspace member controls never offer ownership transfer', () => {
|
||||
const source = read(
|
||||
'src/app/home/components/workspace-settings/WorkspaceSettingsPanel.tsx',
|
||||
|
||||
@@ -1,123 +0,0 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import test from 'node:test';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const currentDirectory = path.dirname(fileURLToPath(import.meta.url));
|
||||
const webRoot = path.resolve(currentDirectory, '../..');
|
||||
|
||||
function readSource(relativePath) {
|
||||
return fs.readFileSync(path.join(webRoot, relativePath), 'utf8');
|
||||
}
|
||||
|
||||
const homeSidebarSource = readSource(
|
||||
'src/app/home/components/home-sidebar/HomeSidebar.tsx',
|
||||
);
|
||||
const botFormSource = readSource(
|
||||
'src/app/home/bots/components/bot-form/BotForm.tsx',
|
||||
);
|
||||
const dynamicFormSource = readSource(
|
||||
'src/app/home/components/dynamic-form/DynamicFormComponent.tsx',
|
||||
);
|
||||
const kbFormSource = readSource(
|
||||
'src/app/home/knowledge/components/kb-form/KBForm.tsx',
|
||||
);
|
||||
const settingsDialogSource = readSource(
|
||||
'src/app/home/components/settings-dialog/SettingsDialog.tsx',
|
||||
);
|
||||
const pluginPageSource = readSource('src/app/home/plugin-pages/page.tsx');
|
||||
const authenticatedPluginResourceSource = readSource(
|
||||
'src/hooks/useAuthenticatedPluginResource.ts',
|
||||
);
|
||||
|
||||
test('keeps bot forms spaced with responsive setup and detail columns', () => {
|
||||
const fieldset = botFormSource.match(
|
||||
/<fieldset\s[\s\S]*?disabled=\{isLoading\}/,
|
||||
)?.[0];
|
||||
assert.ok(fieldset, 'the form must retain its loading-disabled fieldset');
|
||||
assert.match(
|
||||
fieldset,
|
||||
/initBotId\s*\?\s*'grid gap-4 lg:h-full lg:min-h-0 lg:grid-cols-\[minmax\(0,2fr\)_minmax\(0,3fr\)\] lg:grid-rows-\[minmax\(0,1fr\)\]'\s*:\s*'grid items-start gap-6 lg:grid-cols-\[minmax\(16rem,0\.7fr\)_minmax\(0,2fr\)\]'/,
|
||||
);
|
||||
assert.match(kbFormSource, /<form[\s\S]*?className="space-y-6"/);
|
||||
});
|
||||
|
||||
test('hides the manifest connection switch behind the dedicated selector', () => {
|
||||
assert.match(
|
||||
botFormSource,
|
||||
/webhookField\?\.show_if\?\.field\s*\?\s*\[webhookField\.show_if\.field\]/,
|
||||
);
|
||||
assert.match(
|
||||
botFormSource,
|
||||
/hiddenItemNames=\{connectionModeControllerNames\}/,
|
||||
);
|
||||
assert.match(
|
||||
dynamicFormSource,
|
||||
/if \(hiddenItemNames\?\.includes\(config\.name\)\) return null/,
|
||||
);
|
||||
assert.doesNotMatch(
|
||||
dynamicFormSource.match(
|
||||
/const editableItems = useMemo\([\s\S]*?\n \);/,
|
||||
)?.[0] ?? '',
|
||||
/hiddenItemNames/,
|
||||
);
|
||||
});
|
||||
|
||||
test('does not expose storage analysis in Cloud settings or via a deep link', () => {
|
||||
assert.match(
|
||||
homeSidebarSource,
|
||||
/canViewStorageAnalysis\s*&&\s*\(\s*<DropdownMenuItem[\s\S]*?openSettings\('storageAnalysis'\)/,
|
||||
);
|
||||
assert.match(
|
||||
settingsDialogSource,
|
||||
/const canViewStorageAnalysis\s*=\s*currentWorkspace\?\.workspace\.source\s*!==\s*'cloud_projection'\s*&&\s*canViewAudit/,
|
||||
);
|
||||
assert.match(
|
||||
settingsDialogSource,
|
||||
/item\.id === 'storageAnalysis'[\s\S]*?return canViewStorageAnalysis/,
|
||||
);
|
||||
assert.match(
|
||||
settingsDialogSource,
|
||||
/section === 'storageAnalysis' && !canViewStorageAnalysis/,
|
||||
);
|
||||
assert.match(
|
||||
settingsDialogSource,
|
||||
/section === 'storageAnalysis' &&\s*canViewStorageAnalysis &&\s*\(\s*<StorageAnalysisPanel/,
|
||||
);
|
||||
});
|
||||
|
||||
test('renders storage analysis with the storage icon in the user menu', () => {
|
||||
assert.match(
|
||||
homeSidebarSource,
|
||||
/canViewStorageAnalysis\s*&&\s*\(\s*<DropdownMenuItem[\s\S]*?<HardDrive\s*\/>[\s\S]*?\{t\('storageAnalysis\.title'\)\}/,
|
||||
);
|
||||
});
|
||||
|
||||
test('loads plugin pages through the authenticated Workspace-scoped asset route', () => {
|
||||
assert.match(pluginPageSource, /useAuthenticatedPluginAsset/);
|
||||
assert.match(
|
||||
pluginPageSource,
|
||||
/useAuthenticatedPluginAsset\(\s*author,\s*pluginName,\s*pagePath,?\s*\)/,
|
||||
);
|
||||
assert.match(pluginPageSource, /src=\{assetUrl\}/);
|
||||
assert.doesNotMatch(pluginPageSource, /getPluginAssetURL\(/);
|
||||
assert.match(pluginPageSource, /plugins\.loadFailed/);
|
||||
assert.match(pluginPageSource, /loadedAssetUrl !== assetUrl/);
|
||||
});
|
||||
|
||||
test('revokes and reloads authenticated plugin resources when the Workspace changes', () => {
|
||||
assert.match(authenticatedPluginResourceSource, /useCurrentWorkspace/);
|
||||
assert.match(
|
||||
authenticatedPluginResourceSource,
|
||||
/const workspaceUuid = currentWorkspace\?\.workspace\.uuid;/,
|
||||
);
|
||||
assert.match(
|
||||
authenticatedPluginResourceSource,
|
||||
/\[author, name, filepath, resourceKey\]/,
|
||||
);
|
||||
assert.match(
|
||||
authenticatedPluginResourceSource,
|
||||
/resource\.key === resourceKey \? resource\.url : ''/,
|
||||
);
|
||||
});
|
||||
Reference in New Issue
Block a user