Skip to content

Commit 1e01a46

Browse files
test(e2e): realign fixtures with the live app (account-age GitHub gate, account-menu marker, non-member join CTA)
The e2e suite carried pre-existing drift against the current app, unrelated to the demo-sub seed change: - github-dev gates on an account-age badge (provider=github, >= 12 months), but the mock issuer had no account-age profile and specs 06/09 disclosed oauth-account, so every GitHub join failed the gate. Add an account-age badge to the mock catalog and disclose it from those specs. - The signed-in nav marker moved from a 'signed in' text span to the gear 'Account menu' button; expectSignedIn now asserts that button. - A signed-in non-member's composer suppresses the full-width denied card in favor of the sub-forum's Join CTA, so 08b now asserts the 'Join to post' prompt and the absence of a New-post button.
1 parent 7466217 commit 1e01a46

6 files changed

Lines changed: 31 additions & 19 deletions

File tree

e2e/06-poll.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { GITHUB_SLUG, GITHUB_ROLE } from './harness/env';
1212
test('create a poll post and vote, then see the result view', async ({ page }) => {
1313
await joinSubforum(page, {
1414
email: 'pollster@acme.example',
15-
badges: ['oauth-account'],
15+
badges: ['account-age'],
1616
slug: GITHUB_SLUG,
1717
role: GITHUB_ROLE,
1818
pseudonym: 'Pollster'

e2e/08-gate-denied.spec.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,25 @@
33
// Two angles on the badge gate:
44
//
55
// (a) JOIN gate: a user who discloses only an email-domain badge tries to join
6-
// the GitHub-verified-devs sub-forum (which requires an oauth-account github
6+
// the GitHub-verified-devs sub-forum (which requires an account-age github
77
// badge). Minister discloses nothing satisfying, the server re-runs the gate
88
// on the verified disclosure, and the join is REJECTED - the join page
99
// surfaces the failure rather than confirming membership.
1010
//
1111
// (b) Composer gate: a signed-in NON-member viewing the public Ask-an-expert
1212
// sub-forum is NOT offered the answer/post affordance (the gate hides the
13-
// control it would 403). The "you don't have permission" notice shows
14-
// instead of a New-post button.
13+
// control it would 403). A "Join to post" CTA shows in place of a New-post
14+
// button (the composer's full-width denied card is suppressed for a
15+
// non-member since the prominent Join CTA already explains how to gain
16+
// posting access - see PostComposer `hideDeniedCard`).
1517

1618
import { test, expect } from '@playwright/test';
1719
import { signInWithMinister } from './harness/helpers';
1820
import { GITHUB_SLUG, GITHUB_ROLE, ASK_SLUG } from './harness/env';
1921

2022
test('join gate rejects a disclosure that does not satisfy the role', async ({ page }) => {
2123
// Sign in to join github-devs but disclose only email-domain (NOT the required
22-
// oauth-account github badge). The mock issuer mints nothing satisfying.
24+
// account-age github badge). The mock issuer mints nothing satisfying.
2325
await signInWithMinister(page, {
2426
email: 'wrong-badge@acme.example',
2527
badges: ['email-domain'],
@@ -41,14 +43,12 @@ test('a signed-in non-member is not offered the post affordance in Ask-an-expert
4143
}) => {
4244
// Identity-only sign-in: the user is authenticated but is NOT a member of the
4345
// public Ask-an-expert sub-forum. The public role may `ask`/read but holds no
44-
// `post:*`/`answer` grant, so the post composer must render its denied state
45-
// (the gate hides a control it would 403) rather than a New-post button.
46+
// `post:*`/`answer` grant, so the gate hides the post affordance: no New-post
47+
// button, and a "Join to post" CTA takes its place.
4648
await signInWithMinister(page, { email: 'reader@acme.example', badges: ['email-domain'] });
4749
await expect(page).toHaveURL(/\/$/);
4850

4951
await page.goto(`/s/${ASK_SLUG}`);
50-
await expect(
51-
page.getByText("You don't have permission to post here", { exact: false })
52-
).toBeVisible();
52+
await expect(page.getByText('to post, comment, and react', { exact: false })).toBeVisible();
5353
await expect(page.getByRole('button', { name: 'New post' })).toHaveCount(0);
5454
});

e2e/09-github-badge-join.spec.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33
//
44
// The counterpart to spec 8a (deny): there, a user disclosing only an
55
// email-domain badge is REJECTED from github-devs. Here the user discloses the
6-
// required oauth-account (provider=github) badge, so the whole disclosure path
7-
// runs green end to end:
6+
// required account-age (provider=github, >= 12 months) badge, so the whole
7+
// disclosure path runs green end to end:
88
//
99
// /api/auth/oidc/start?subforum=github-devs&role=github-dev
10-
// -> the role's policy { badge: oauth-account, where: { provider: github } }
11-
// rides along as `minister_policy` and adds the `badge:oauth-account`
10+
// -> the role's policy { badge: account-age, where: { provider: github } }
11+
// rides along as `minister_policy` and adds the `badge:account-age`
1212
// scope, so the mock issuer discloses exactly that badge (minimal set);
1313
// -> the callback re-verifies the id_token + the disclosed VC and stashes a
1414
// single-use pending-join;
@@ -24,10 +24,10 @@ import { test, expect } from '@playwright/test';
2424
import { joinSubforum } from './harness/helpers';
2525
import { GITHUB_SLUG, GITHUB_ROLE } from './harness/env';
2626

27-
test('joins github-devs by disclosing a GitHub oauth-account badge', async ({ page }) => {
27+
test('joins github-devs by disclosing a GitHub account-age badge', async ({ page }) => {
2828
await joinSubforum(page, {
2929
email: 'join-dev@acme.example',
30-
badges: ['oauth-account'],
30+
badges: ['account-age'],
3131
slug: GITHUB_SLUG,
3232
role: GITHUB_ROLE,
3333
pseudonym: 'OctoJoiner'

e2e/harness/env.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ export const COMPANY_DOMAIN = 'acme.example';
7575
export const COMPANY_SLUG = 'acme-employees';
7676
export const COMPANY_ROLE = 'employee';
7777

78-
/** GitHub-verified devs: oauth-account provider=github. */
78+
/** GitHub-verified devs: account-age provider=github (>= 12 months, no handle). */
7979
export const GITHUB_SLUG = 'github-devs';
8080
export const GITHUB_ROLE = 'github-dev';
8181

e2e/harness/helpers.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,12 @@ export async function signInWithMinister(page: Page, opts: SignInOpts): Promise<
4242
await Promise.all([page.waitForURL(/localhost/), page.click('#approve')]);
4343
}
4444

45-
/** Assert the top-nav shows the signed-in marker (the user landed authenticated). */
45+
/** Assert the top-nav shows the signed-in marker (the user landed authenticated).
46+
* The signed-in state renders the gear-triggered account menu (aria-label
47+
* "Account menu"); a signed-out nav shows the "Sign in with Minister" button
48+
* instead, so the menu button's presence is the authenticated marker. */
4649
export async function expectSignedIn(page: Page): Promise<void> {
47-
await expect(page.getByText('signed in')).toBeVisible();
50+
await expect(page.getByRole('button', { name: 'Account menu' })).toBeVisible();
4851
}
4952

5053
export interface JoinOpts {

e2e/mock-oidc/issuer.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,14 @@ const BADGE_CATALOG: Record<string, MockBadge> = {
219219
type: 'oauth-account',
220220
attributes: { provider: 'github', accountId: 'gh-e2e-1' }
221221
},
222+
// The launch GitHub-Verified Devs role gates on account AGE (provider=github,
223+
// >= 12 months), not the oauth-account handle. `olderThanMonths` is the coarse
224+
// lower-bound bucket Minister discloses; the role policy only constrains
225+
// `provider`, so any bucket satisfies it.
226+
'account-age': {
227+
type: 'account-age',
228+
attributes: { provider: 'github', olderThanMonths: 12 }
229+
},
222230
'invite-code': { type: 'invite-code', attributes: { label: 'WELCOME' } },
223231
'age-over-21': { type: 'age-over-21', attributes: { threshold: 21 } }
224232
};
@@ -346,6 +354,7 @@ async function handle(req: IncomingMessage, res: ServerResponse, issuer: string)
346354
'profile',
347355
'badge:email-domain',
348356
'badge:oauth-account',
357+
'badge:account-age',
349358
'badge:invite-code',
350359
'badge:age-over-21'
351360
],

0 commit comments

Comments
 (0)