Ctrl K
ComunidadGuías…

tests/a11y/global-setup.js

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
// Signs in as the seeded superadmin, adds the content the seed leaves out (wiki
// pages, an own gist), and resolves every {placeholder} in routes.js to a real
// path on this server. Discovery instead of hard-coded names keeps the gate
// working when the seed's output changes.
import { chromium } from '@playwright/test';
import fs from 'node:fs';
import { baseURL } from './playwright.config.js';

export const ADMIN = { email: 'admin@example.test', username: 'siteadmin', password: 'cloudzilla-seed' };
export const WIKI_PAGES = ['Home', 'Architecture', 'Contributing'];

export default async function globalSetup() {
  fs.mkdirSync('.cache', { recursive: true });
  const browser = await chromium.launch();
  const page = await browser.newPage({ baseURL });

  await page.goto('/login');
  await page.getByLabel('Email').fill(ADMIN.email);
  await page.getByLabel('Password', { exact: true }).fill(ADMIN.password);
  await Promise.all([page.waitForURL(u => !u.pathname.startsWith('/login')), page.getByRole('button', { name: 'Sign in' }).click()]);
  await page.context().storageState({ path: '.cache/admin.json' });

  const csrf = (await page.context().cookies()).find(c => c.name === 'csrf_token')?.value ?? '';
  const api = (method, path, opts = {}) =>
    page.request.fetch(path, { method, headers: { 'X-CSRF-Token': csrf, ...opts.headers }, ...opts }).then(async res => {
      if (!res.ok() && res.status() !== 303) throw new Error(`${method} ${path}: ${res.status()} ${await res.text()}`);
      return res;
    });

  async function links(path, pattern) {
    const res = await page.goto(path);
    if (!res.ok()) return [];
    const hrefs = await page.locator('main a[href]').evaluateAll(as => as.map(a => a.getAttribute('href')));
    return hrefs.filter(h => pattern.test(h.split(/[?#]/)[0])).map(h => h.split('#')[0]);
  }
  async function first(paths, pattern) {
    for (const p of paths) {
      const [hit] = await links(p, pattern);
      if (hit) return hit;
    }
    throw new Error(`no link matching ${pattern} on ${paths.join(', ')}`);
  }

  let repos = await (await api('GET', '/api/repos/')).json();
  const ownRepo = `/${ADMIN.username}/a11y-fixture`;
  if (!repos.some(r => r.owner_name === ADMIN.username && r.name === 'a11y-fixture')) {
    await api('POST', '/api/repos/', { data: { name: 'a11y-fixture', add_readme: true, private: false } });
    repos = await (await api('GET', '/api/repos/')).json();
  }
  const orgCheck = await page.request.get('/api/orgs/a11y-fixture-org');
  if (orgCheck.status() === 404) {
    await api('POST', '/api/orgs/', { data: { name: 'a11y-fixture-org', display_name: 'A11y fixture' } });
  } else if (!orgCheck.ok()) throw new Error(`Cannot inspect fixture organization: ${orgCheck.status()}`);

  for (const slug of WIKI_PAGES) {
    await api('POST', `/api/repos${ownRepo}/wiki/${slug}`, {
      form: { content: `# ${slug}\n\nSee [the README](../) and [${WIKI_PAGES[0]}](${WIKI_PAGES[0]}).`, message: `Add ${slug}` },
      maxRedirects: 0,
    });
  }
  await page.goto('/gists');
  const existingGist = page.locator('li[data-name="a11y fixture siteadmin"] > a').first();
  let gistPath = await existingGist.count() ? await existingGist.getAttribute('href') : null;
  if (!gistPath) {
    const gist = await (await api('POST', '/api/gists', {
      data: { description: 'a11y fixture', public: true, files: [{ filename: 'main.go', content: 'package main\n\nfunc main() {}\n' }] },
    })).json();
    gistPath = `/gists/${gist.id}`;
  }

  // The busiest public repo carries the issue, PR and discussion pages.
  const publicRepos = repos.filter(r => !r.private && !r.is_archived && r.name !== 'a11y-fixture').map(r => `/${r.owner_name}/${r.name}`);
  const counts = await Promise.all(
    publicRepos.map(async p => (await (await api('GET', `/api/repos${p}/issues/`)).json()).length),
  );
  const busy = publicRepos.map((p, i) => [p, counts[i]]).sort((a, b) => b[1] - a[1]).map(([p]) => p);
  const repo = busy[0];
  const each = suffix => busy.map(p => p + suffix);
  const num = s => new RegExp(`^/[^/]+/[^/]+/${s}/\\d+$`);

  const fixtures = {
    me: ADMIN.username,
    repo,
    ownRepo,
    wiki: WIKI_PAGES[0],
    gist: gistPath,
    blob: await first([repo], /^\/[^/]+\/[^/]+\/blob\/.+/),
    commit: await first([`${repo}/commits`], /^\/[^/]+\/[^/]+\/commit\/[0-9a-f]{7,}$/),
    issue: await first([`${repo}/issues`], num('issues')),
    closedIssue: await first(each('/issues?state=closed'), num('issues')),
    milestone: await first(each('/milestones'), num('milestones')),
    pull: await first(each('/pulls'), num('pulls')),
    discussion: await first(each('/discussions'), num('discussions')),
    project: await first(each('/projects'), num('projects')),
    release: await first(each('/releases'), /^\/[^/]+\/[^/]+\/releases\/tag\/.+$/),
    org: 'a11y-fixture-org',
    user: repos.find(r => !r.org_id && r.owner_name !== ADMIN.username).owner_name,
  };
  const repoOf = path => path.split('/').slice(0, 3).join('/');
  Object.assign(fixtures, {
    blame: fixtures.blob.replace('/blob/', '/blame/'),
    milestoneRepo: repoOf(fixtures.milestone),
    discussionRepo: repoOf(fixtures.discussion),
    projectRepo: repoOf(fixtures.project),
    releaseRepo: repoOf(fixtures.release),
  });
  fs.writeFileSync('.cache/fixtures.json', JSON.stringify(fixtures, null, 2));
  await browser.close();
}