Skip to content

Commit 05b8ee4

Browse files
committed
test(org): add the organization redesign acceptance suite
1 parent 6950d03 commit 05b8ee4

11 files changed

Lines changed: 3896 additions & 5 deletions

File tree

‎.github/ci-suites.json‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@
2424
"group": "organization-search",
2525
"task": "ci:e2e-organization-search"
2626
},
27+
{
28+
"group": "org-redesign",
29+
"task": "ci:e2e-org-redesign"
30+
},
2731
{
2832
"group": "browser-extension-navigation",
2933
"task": "ci:e2e-browser-extension"

‎.github/scripts/ci-plan.gql‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ query($base: String!, $head: String!) {
33
affectedTasks(base: $base, head: $head, tasks: [
44
"test", "build", "type-check", "ci:integration", "ci:desktop-live",
55
"ci:e2e-scim", "ci:e2e-cli", "ci:e2e-stop-after", "ci:e2e-desktop-inbox",
6-
"ci:e2e-assistant-actions", "ci:e2e-organization-search",
6+
"ci:e2e-assistant-actions", "ci:e2e-organization-search", "ci:e2e-org-redesign",
77
"ci:e2e-docs-platform",
88
"ci:e2e-browser-extension", "ci:e2e-project-files", "ci:e2e-mobile", "ci:e2e-seo"
99
]) {

‎.github/scripts/http-e2e.sh‎

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# CI groups, which reuse the production build from `e2e-build`.
44
# The job extracts it into apps/sim/.next before running these suites.
55
#
6-
# Usage: http-e2e.sh <scim|cli|stop-after|desktop-inbox|assistant-actions|organization-search|browser-extension|browser-extension-native|browser-extension-navigation|browser-extension-composer|browser-extension-access|project-files|mobile|seo> (run from apps/sim)
6+
# Usage: http-e2e.sh <scim|cli|stop-after|desktop-inbox|assistant-actions|organization-search|org-redesign|browser-extension|browser-extension-native|browser-extension-navigation|browser-extension-composer|browser-extension-access|project-files|mobile|seo> (run from apps/sim)
77
#
88
# The job provides DATABASE_URL, BETTER_AUTH_SECRET and ENCRYPTION_KEY; each group sets the rest of
99
# its app's environment here. Reports and server logs land in $RUNNER_TEMP/e2e.
@@ -20,7 +20,7 @@
2020
# telemetry flush runs detached and still writes .next/dev).
2121
set -euo pipefail
2222

23-
group=${1:?usage: http-e2e.sh <scim|cli|stop-after|desktop-inbox|assistant-actions|organization-search|browser-extension|browser-extension-native|browser-extension-navigation|browser-extension-composer|browser-extension-access|project-files|mobile|seo>}
23+
group=${1:?usage: http-e2e.sh <scim|cli|stop-after|desktop-inbox|assistant-actions|organization-search|org-redesign|browser-extension|browser-extension-native|browser-extension-navigation|browser-extension-composer|browser-extension-access|project-files|mobile|seo>}
2424
report_dir="$RUNNER_TEMP/e2e"
2525
ready_timeout_seconds=600
2626
mkdir -p "$report_dir"
@@ -32,6 +32,7 @@ status_log=''
3232
realtime_pid=''
3333
realtime_tag=''
3434
realtime_log=''
35+
agent_pid=''
3536
browsers_pid=''
3637
local_app_url=''
3738
# `dev` or `start`; a group sets it before start_app.
@@ -63,6 +64,10 @@ finish() {
6364
tail -n 100 "$realtime_log"
6465
fi
6566
fi
67+
if [ -n "$agent_pid" ]; then
68+
kill "$agent_pid" 2>/dev/null || true
69+
wait "$agent_pid" 2>/dev/null || true
70+
fi
6671
if [ -n "$browsers_pid" ]; then
6772
kill -- "-$browsers_pid" 2>/dev/null || true
6873
wait "$browsers_pid" 2>/dev/null || true
@@ -133,6 +138,13 @@ start_realtime() {
133138
wait_ready "$realtime_pid" "http://127.0.0.1:$port/health" "$name realtime server"
134139
}
135140

141+
# stop_app: stops the app start_app started, so a group can start it again under other flags.
142+
stop_app() {
143+
bash "$GITHUB_WORKSPACE/.github/scripts/stop-session.sh" "$server_pid" "$app_tag"
144+
wait "$server_pid" 2>/dev/null || true
145+
server_pid=''
146+
}
147+
136148
# wait_ready <pid> <health-url> <label>
137149
wait_ready() {
138150
local pid=$1 url=$2 label=$3
@@ -268,6 +280,56 @@ case "$group" in
268280
esac
269281
;;
270282

283+
# One hosted Enterprise organization shaped like a real customer, a scripted worker in place of the
284+
# model, and the app twice: as that customer has it, then with People on. Hosted is decided by the
285+
# app's hostname, which the job maps to loopback. Both phases report, whichever fails.
286+
org-redesign)
287+
app_server=start
288+
export REDIS_URL=redis://127.0.0.1:6379
289+
export E2E_APP_PUBLIC_URL=http://org-redesign.sim.ai:3029
290+
export INTERNAL_API_BASE_URL=http://127.0.0.1:3029 TRUSTED_ORIGINS=http://127.0.0.1:3029
291+
export NEXT_PUBLIC_SOCKET_URL=http://127.0.0.1:3030 SOCKET_SERVER_URL=http://127.0.0.1:3030
292+
export BILLING_ENABLED=true NEXT_PUBLIC_BILLING_ENABLED=true
293+
export ENTERPRISE_ENABLED=true NEXT_PUBLIC_ENTERPRISE_ENABLED=true
294+
export ORGANIZATIONS_ENABLED=true NEXT_PUBLIC_ORGANIZATIONS_ENABLED=true
295+
export SSO_ENABLED=true NEXT_PUBLIC_SSO_ENABLED=true
296+
export KNOWLEDGE_MEMBER_ACCESS=true CREDENTIAL_GROUPS=true ACCESS_CONTROL_ENABLED=true
297+
export NEXT_PUBLIC_ACCESS_CONTROL_ENABLED=true SIM_LINKS=true
298+
export COPILOT_TOOL_PERMISSIONS_ENABLED=true
299+
export INTERNAL_API_SECRET=org-redesign-ci-local-secret-at-least-32-characters
300+
export COPILOT_API_KEY=org-redesign-ci-local-copilot-key MOTHERSHIP_SIM_TRANSPORT=direct
301+
export SIM_AGENT_API_URL=http://127.0.0.1:3031
302+
export GOOGLE_CLIENT_ID=org-redesign-google-client GOOGLE_CLIENT_SECRET=org-redesign-google-secret
303+
export JIRA_CLIENT_ID=org-redesign-jira-client JIRA_CLIENT_SECRET=org-redesign-jira-secret
304+
export CONFLUENCE_CLIENT_ID=org-redesign-confluence-client CONFLUENCE_CLIENT_SECRET=org-redesign-confluence-secret
305+
export STRIPE_SECRET_KEY=sk_test_org_redesign STRIPE_WEBHOOK_SECRET=whsec_org_redesign
306+
export DB_TX_TRIPWIRE=throw
307+
bun --no-env-file scripts/org-redesign-seed.ts
308+
start_browser_install org-redesign --only-shell chromium
309+
bun --no-env-file scripts/org-redesign-e2e/scripted-agent.ts 3031 \
310+
> "$report_dir/org-redesign-agent.log" 2>&1 &
311+
agent_pid=$!
312+
start_app org-redesign 3029 'organization redesign' record-http-status
313+
start_realtime org-redesign 3030
314+
wait_for_browsers
315+
run_status=0
316+
ORG_REDESIGN_E2E_ORIGIN="$E2E_APP_PUBLIC_URL" \
317+
ORG_REDESIGN_E2E_DATABASE_URL="$DATABASE_URL" \
318+
ORG_REDESIGN_E2E_AUTH_SECRET="$BETTER_AUTH_SECRET" \
319+
ORG_REDESIGN_E2E_REPORT_PATH="$report_dir/org-redesign-ui-report.json" \
320+
bun --no-env-file scripts/test-org-redesign-e2e.ts || run_status=$?
321+
stop_app
322+
export PEOPLE=true
323+
start_app org-redesign-people 3029 'organization redesign, People on'
324+
ORG_REDESIGN_E2E_PHASE=people \
325+
ORG_REDESIGN_E2E_ORIGIN="$E2E_APP_PUBLIC_URL" \
326+
ORG_REDESIGN_E2E_DATABASE_URL="$DATABASE_URL" \
327+
ORG_REDESIGN_E2E_AUTH_SECRET="$BETTER_AUTH_SECRET" \
328+
ORG_REDESIGN_E2E_REPORT_PATH="$report_dir/org-redesign-people-ui-report.json" \
329+
bun --no-env-file scripts/test-org-redesign-e2e.ts || run_status=$?
330+
exit "$run_status"
331+
;;
332+
271333
browser-extension|browser-extension-native|browser-extension-navigation|browser-extension-composer|browser-extension-access)
272334
extension_group=all
273335
case "$group" in

‎.github/workflows/checks.yml‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ jobs:
207207
needs: [changes, e2e-build]
208208
if: needs.changes.outputs.http == 'true'
209209
runs-on: ubuntu-24.04
210-
timeout-minutes: 20
210+
timeout-minutes: ${{ matrix.group == 'org-redesign' && 45 || 20 }}
211211
strategy:
212212
fail-fast: false
213213
matrix: ${{ fromJSON(needs.changes.outputs.http_matrix) }}
@@ -227,7 +227,7 @@ jobs:
227227
--health-retries 10
228228
# Desktop inbox, browser extension, and Project Files use Redis.
229229
redis:
230-
image: ${{ (matrix.group == 'desktop-inbox' || matrix.group == 'assistant-actions' || matrix.group == 'organization-search' || startsWith(matrix.group, 'browser-extension-') || matrix.group == 'project-files') && 'redis:8.2-alpine' || '' }}
230+
image: ${{ (matrix.group == 'desktop-inbox' || matrix.group == 'assistant-actions' || matrix.group == 'organization-search' || matrix.group == 'org-redesign' || startsWith(matrix.group, 'browser-extension-') || matrix.group == 'project-files') && 'redis:8.2-alpine' || '' }}
231231
ports:
232232
- 6379:6379
233233
options: >-
@@ -293,6 +293,10 @@ jobs:
293293
if: matrix.group == 'scim'
294294
run: printf '127.0.0.1 scim-e2e.sim.ai\n' | sudo tee -a /etc/hosts
295295

296+
- name: Map the hosted organization fixture to loopback
297+
if: matrix.group == 'org-redesign'
298+
run: printf '127.0.0.1 org-redesign.sim.ai\n' | sudo tee -a /etc/hosts
299+
296300
# No step timeout: the job's bound covers a hang without cutting a slow but healthy suite
297301
# short of writing its report.
298302
- name: Run end-to-end suites

‎apps/sim/package.json‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
"ci:e2e-desktop-inbox": "bash ../../.github/scripts/http-e2e.sh desktop-inbox",
5454
"ci:e2e-assistant-actions": "bash ../../.github/scripts/http-e2e.sh assistant-actions",
5555
"ci:e2e-organization-search": "bash ../../.github/scripts/http-e2e.sh organization-search",
56+
"ci:e2e-org-redesign": "bash ../../.github/scripts/http-e2e.sh org-redesign",
5657
"ci:e2e-docs-platform": "bun --no-env-file scripts/test-docs-search-provider-e2e.ts",
5758
"ci:e2e-project-files": "bash ../../.github/scripts/http-e2e.sh project-files",
5859
"ci:e2e-mobile": "bash ../../.github/scripts/http-e2e.sh mobile",
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
/**
2+
* The organization `test-org-redesign-e2e.ts` runs against, shared with its seed: Enterprise, a
3+
* small admin team over a large group of members who cannot build, and made-up names throughout.
4+
*/
5+
export const ORGANIZATION_ID = 'org-redesign-organization'
6+
export const OUTSIDE_ORGANIZATION_ID = 'org-redesign-outside'
7+
export const ORGANIZATION_NAME = 'Ridgeline Outfitters'
8+
export const PASSWORD = 'org-redesign-password-1'
9+
export const LINK_COUNT = 183
10+
11+
const person = (key: string, name: string, role: 'owner' | 'admin' | 'member') => ({
12+
key,
13+
name,
14+
role,
15+
userId: `org-redesign-user-${key}`,
16+
email: `${key}@org-redesign.test`,
17+
sessionToken: `org-redesign-session-${key}`,
18+
})
19+
20+
export const OWNER = person('owner', 'Olive Owner', 'owner')
21+
export const ADMIN = person('admin', 'Ada Admin', 'admin')
22+
/** Connected to nothing, the most common member today. */
23+
export const MEMBER = person('member', 'Mia Member', 'member')
24+
/** A member of the same group with managed Google accounts. */
25+
export const CONNECTED = person('connected', 'Cory Connected', 'member')
26+
/** A member of a much narrower group, with no workspaces. */
27+
export const NARROW = person('narrow', 'Nia Narrow', 'member')
28+
/** Belongs to another organization only. */
29+
export const OUTSIDER = person('outsider', 'Otto Outsider', 'owner')
30+
31+
export const FILLERS = [
32+
person('filler-1', 'Finn Fielding', 'member'),
33+
person('filler-2', 'Gwen Garza', 'member'),
34+
person('filler-3', 'Hugo Hale', 'member'),
35+
person('filler-4', 'Ivy Ingram', 'member'),
36+
] as const
37+
38+
export const IN_ORGANIZATION = [OWNER, ADMIN, MEMBER, CONNECTED, NARROW, ...FILLERS] as const
39+
export const EVERYONE = [...IN_ORGANIZATION, OUTSIDER] as const
40+
41+
export const STANDARD_GROUP_ID = 'org-redesign-group-standard'
42+
export const NARROW_GROUP_ID = 'org-redesign-group-narrow'
43+
export const FULL_GROUP_ID = 'org-redesign-group-full'
44+
45+
/** The shape of the group most members belong to. */
46+
export const STANDARD_GROUP_CONFIG = {
47+
disableInvitations: true,
48+
disableToolAutoApproval: true,
49+
disableLogExport: true,
50+
disablePublicApi: true,
51+
hideInboxTab: true,
52+
disablePersonalCredentials: false,
53+
disableWorkspaceCreation: false,
54+
hideOrgMemberDirectory: false,
55+
deniedModels: ['claude-opus-4-5', 'claude-fable-1'],
56+
allowedIntegrations: [
57+
'gmail_v2',
58+
'google_calendar_v2',
59+
'google_drive',
60+
'slack_v2',
61+
'jira',
62+
'confluence_v2',
63+
'gitlab',
64+
'zoom',
65+
],
66+
allowedKnowledgeConnectors: ['confluence', 'gitlab', 'slack', 'jira', 'jsm'],
67+
}
68+
69+
export const NARROW_GROUP_CONFIG = {
70+
...STANDARD_GROUP_CONFIG,
71+
allowedIntegrations: ['slack', 'slack_v2', 'managed_agent', 'api'],
72+
allowedKnowledgeConnectors: ['slack'],
73+
}
74+
75+
/** Approved search sources; only `coda` and `lucid` hold a live-search policy. */
76+
export const APPROVED_SOURCES = [
77+
'gmail',
78+
'google_calendar',
79+
'google_drive',
80+
'jira',
81+
'slack',
82+
'confluence',
83+
'gitlab',
84+
'coda',
85+
'lucid',
86+
] as const
87+
88+
/** Credential group options a member can connect through. No Microsoft provider is on offer. */
89+
export const CONNECTABLE_PROVIDERS = [
90+
'gmail',
91+
'google-calendar',
92+
'google-drive',
93+
'jira',
94+
'confluence',
95+
] as const
96+
97+
export const GRANTS = {
98+
gmail: { credentialId: 'org-redesign-grant-gmail', providerId: 'google-email' },
99+
'google-calendar': {
100+
credentialId: 'org-redesign-grant-google-calendar',
101+
providerId: 'google-calendar',
102+
},
103+
} as const
104+
105+
const workspaceId = (slug: string) => `org-redesign-workspace-${slug}`
106+
107+
/** More than one page of the rail's list, so its paging is on for an admin. */
108+
export const WORKSPACES = [
109+
{ id: workspaceId('operations'), name: 'Operations' },
110+
{ id: workspaceId('marketing'), name: 'Marketing' },
111+
{ id: workspaceId('service'), name: 'Service Desk' },
112+
{ id: workspaceId('parts'), name: 'Parts Catalog' },
113+
{ id: workspaceId('finance'), name: 'Finance' },
114+
{ id: workspaceId('fleet'), name: 'Fleet' },
115+
{ id: workspaceId('training'), name: 'Training' },
116+
] as const
117+
export const MEMBER_ADMIN_WORKSPACE = WORKSPACES[0]
118+
export const MEMBER_WRITE_WORKSPACE = WORKSPACES[1]
119+
120+
const uuid = (digit: string) =>
121+
`${digit.repeat(8)}-${digit.repeat(4)}-4${digit.repeat(3)}-8${digit.repeat(3)}-${digit.repeat(12)}`
122+
123+
/** The member's chats: assistant ones live under Search, and an agent one they can no longer open. */
124+
export const MEMBER_CHATS = {
125+
assistant: { id: uuid('1'), title: 'Warranty coverage', mode: 'assistant', seen: true },
126+
unread: { id: uuid('2'), title: 'Dealer onboarding', mode: 'assistant', seen: false },
127+
removable: { id: uuid('3'), title: 'Old parts question', mode: 'assistant', seen: true },
128+
bulkOne: { id: uuid('4'), title: 'Bulk removal one', mode: 'assistant', seen: true },
129+
bulkTwo: { id: uuid('5'), title: 'Bulk removal two', mode: 'assistant', seen: true },
130+
agent: { id: uuid('6'), title: 'Agent from before', mode: 'agent', seen: true },
131+
} as const
132+
133+
export const ADMIN_CHATS = {
134+
agent: { id: uuid('7'), title: 'Quarterly review', mode: 'agent', seen: true },
135+
assistant: { id: uuid('8'), title: 'Vendor renewals', mode: 'assistant', seen: false },
136+
deleted: { id: uuid('9'), title: 'Retired plan', mode: 'agent', seen: true },
137+
} as const
138+
139+
/** Recognizable rows in the 183, beside the numbered ones. */
140+
export const NAMED_LINKS = {
141+
handbook: { name: 'handbook', url: 'https://example.com/handbook', description: 'The handbook' },
142+
restricted: { name: 'payroll', url: 'https://payroll.example.com', description: 'Pay stubs' },
143+
unlisted: { name: 'skunkworks', url: 'https://skunk.example.com', description: 'Quiet project' },
144+
variable: {
145+
name: 'ticket',
146+
url: 'https://tickets.example.com/browse/{*}',
147+
description: 'Open a ticket',
148+
},
149+
mostUsed: { name: 'timesheet', url: 'https://time.example.com', description: 'Weekly hours' },
150+
} as const
151+
152+
export const SEEDED_SOURCE = {
153+
url: 'https://docs.example.com/service-bulletin',
154+
title: 'Service bulletin',
155+
query: 'service bulletin',
156+
}

0 commit comments

Comments
 (0)