TenantAtlas/apps/website/tests/smoke/home-product.spec.ts
ahmido 2000c17f33 feat: transition website product page to platform (#391)
## Summary
- rename the website product page to `/platform`
- add a redirect from `/product` to `/platform` and update navigation/content links
- refresh footer/layout metadata and align smoke tests with the new route
- add spec artifacts for 401-tenantial-platform-page

## Testing
- not run in this step

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #391
2026-05-19 21:34:31 +00:00

392 lines
17 KiB
TypeScript

import { expect, test } from '@playwright/test';
import {
expectCompatibilityRedirect,
expectCtaHierarchy,
expectDisclosureLayer,
expectFooterLinks,
expectHomepageHeroCtaPair,
expectHomepageHeroOrder,
expectHomepageHeroRouteTargets,
expectHomepageHeroStructure,
expectHomepageHeroVisibleOnMobile,
expectHomepageSectionOrder,
expectMobileReadability,
expectNavigationVsCtaDifferentiation,
expectNoBodyHorizontalOverflow,
expectOnwardRouteReachable,
expectPageFamily,
expectPrimaryNavigation,
expectShell,
visitPage,
} from './smoke-helpers';
const forbiddenHomepageTerms = [
'AstroDeck',
'Open Source',
'MIT Licensed',
'TenantCTRL',
'TenantPilot',
'TenantAtlas',
] as const;
const forbiddenPlatformTerms: Array<[string, RegExp]> = [
['AstroDeck', /AstroDeck/i],
['TemplateDeck', /TemplateDeck/i],
['Open Source', /Open Source/i],
['MIT', /\bMIT\b/i],
['TenantAtlas', /TenantAtlas/i],
['TenantPilot', /TenantPilot/i],
['TenantCTRL', /TenantCTRL/i],
] as const;
const unsupportedPlatformClaims = [
/SOC 2/i,
/\bISO(?:\s?\d+)?\b/i,
/HIPAA/i,
/blanket GDPR/i,
/end-to-end encryption/i,
/guaranteed recovery/i,
/guaranteed compliance/i,
/zero drift/i,
/real-time everywhere/i,
/trusted by/i,
/customer logos/i,
/Microsoft certification/i,
/Microsoft partnership/i,
] as const;
async function expectForbiddenHomepageResidueAbsent(page: import('@playwright/test').Page): Promise<void> {
const body = page.locator('body');
const metadata = await page.locator('head').evaluate((head) => {
const title = document.title;
const meta = Array.from(head.querySelectorAll('meta'))
.map((element) => element.getAttribute('content') ?? '')
.join(' ');
const canonical = head.querySelector('link[rel="canonical"]')?.getAttribute('href') ?? '';
return `${title} ${meta} ${canonical}`;
});
for (const term of forbiddenHomepageTerms) {
await expect(body).not.toContainText(new RegExp(term, 'i'));
expect(metadata, `Homepage metadata should not contain ${term}`).not.toMatch(new RegExp(term, 'i'));
}
}
async function expectPlatformResidueAbsent(page: import('@playwright/test').Page): Promise<void> {
const body = page.locator('body');
const metadata = await page.locator('head').evaluate((head) => {
const title = document.title;
const meta = Array.from(head.querySelectorAll('meta'))
.map((element) => element.getAttribute('content') ?? '')
.join(' ');
const canonical = head.querySelector('link[rel="canonical"]')?.getAttribute('href') ?? '';
return `${title} ${meta} ${canonical}`;
});
for (const [term, pattern] of forbiddenPlatformTerms) {
await expect(body).not.toContainText(pattern);
expect(metadata, `Platform metadata should not contain ${term}`).not.toMatch(pattern);
}
}
test('home first read positions Tenantial with one clear action hierarchy', async ({ page }) => {
await visitPage(page, '/');
await expectShell(page, 'Evidence-first governance for Microsoft tenants.');
await expectPageFamily(page, 'landing');
await expectDisclosureLayer(page, '1');
await expectDisclosureLayer(page, '2');
await expectPrimaryNavigation(page);
await expectNavigationVsCtaDifferentiation(page);
await expectFooterLinks(page);
await expectCtaHierarchy(page, 'Book a demo', 'Explore the platform');
await expect(page.getByRole('main').getByRole('link', { name: 'Book a demo' }).first()).toBeVisible();
await expect(page.getByRole('main').getByRole('link', { name: 'Explore the platform' }).first()).toBeVisible();
await expect(page.getByRole('heading', { level: 1 })).toHaveCount(1);
await expectForbiddenHomepageResidueAbsent(page);
const skipLink = page.getByRole('link', { name: 'Skip to content' });
await page.keyboard.press('Tab');
await expect(skipLink).toBeFocused();
});
test('homepage hero explains Tenantial, Microsoft tenant context, and platform CTA route', async ({ page }) => {
await visitPage(page, '/');
await expectHomepageHeroStructure(page);
await expect(page.locator('[data-homepage-hero="true"] [data-hero-eyebrow]')).toContainText(
/governance that earns trust/i,
);
await expect(
page.locator('[data-homepage-hero="true"] [data-hero-heading]').getByRole('heading', {
level: 1,
name: 'Evidence-first governance for Microsoft tenants.',
}),
).toBeVisible();
await expect(page.locator('[data-homepage-hero="true"] [data-hero-supporting-copy]')).toContainText(
/backup and restore with confidence\. detect drift before it becomes audit work\. preserve snapshot history/i,
);
await expectHomepageHeroCtaPair(page, 'Book a demo', 'Explore the platform');
await expectHomepageHeroRouteTargets(page, ['/contact', '/platform']);
});
test('homepage uses neutral trust statements and the six required feature pillars', async ({ page }) => {
await visitPage(page, '/');
await expect(page.locator('[data-section="trustbar"]')).toBeVisible();
await expect(page.locator('[data-section="trustbar"]')).toContainText(/Microsoft tenant focused/i);
await expect(page.locator('[data-section="trustbar"]')).toContainText(/Evidence-oriented workflows/i);
await expect(page.locator('[data-section="trustbar"]')).toContainText(/Designed for audit review/i);
await expect(page.locator('[data-section="trustbar"]')).toContainText(/Operator-led governance/i);
const pillars = page.locator('[data-section="feature-pillars"]');
await expect(pillars).toBeVisible();
for (const capability of ['Backup', 'Restore', 'Drift Detection', 'Evidence', 'Audit Trail', 'Governance Reviews']) {
await expect(pillars.getByRole('heading', { name: capability, exact: true })).toBeVisible();
}
await expect(page.locator('body')).not.toContainText(/SOC 2|ISO\s?\d*|99\.9%|trusted by|customer logos/i);
});
test('homepage dashboard preview is static, responsive, and explains status without color alone', async ({
page,
}) => {
await visitPage(page, '/');
const preview = page.locator('[data-dashboard-preview]').first();
await expect(preview).toBeVisible();
await expect(preview).toContainText('Static demo preview');
await expect(preview).toContainText('Demo values');
await expect(preview).toContainText('92%');
await expect(preview).toContainText('14');
await expect(preview).toContainText('7');
await expect(preview).toContainText('1,248');
await expect(preview).toContainText('98%');
for (const panel of [
'Recent findings',
'Drift timeline',
'Backups and restores',
'Governance reviews',
'Evidence spotlight',
]) {
await expect(preview.getByText(panel, { exact: true })).toBeVisible();
}
for (const status of ['Healthy', 'Review required', 'Critical', 'Review-ready']) {
await expect(preview.getByText(status, { exact: true }).first()).toBeVisible();
}
await expect(preview).not.toContainText(/real[- ]?time|streaming|live tenant feed|May 19|Updated 2m ago/i);
});
test('homepage keeps the final CTA and launch-readiness sections in order', async ({ page }) => {
await visitPage(page, '/');
await expectHomepageSectionOrder(page, ['hero', 'trustbar', 'feature-pillars', 'cta']);
await expect(page.locator('[data-section="cta"]')).toContainText(
'Build tenant governance on evidence, not assumptions.',
);
await expectOnwardRouteReachable(page, ['/platform', '/contact']);
});
test.describe('homepage mobile', () => {
test.use({ viewport: { width: 390, height: 844 } });
test('homepage remains readable on narrow screens without body overflow', async ({ page }) => {
await visitPage(page, '/');
await expectMobileReadability(page);
await expectNoBodyHorizontalOverflow(page);
await expect(page.locator('[data-section="trustbar"]')).toBeVisible();
await expect(page.locator('[data-section="feature-pillars"]')).toBeVisible();
await expect(page.locator('[data-dashboard-preview]').first()).toBeVisible();
});
test('homepage hero preserves meaning order and hero route intent on narrow screens', async ({ page }) => {
await visitPage(page, '/');
await expectHomepageHeroOrder(page, [
'eyebrow',
'headline',
'supporting-copy',
'cta-pair',
'trust-subclaims',
'product-near-visual',
]);
await expectHomepageHeroVisibleOnMobile(page);
await expectHomepageHeroRouteTargets(page, ['/contact', '/platform']);
});
});
test('platform hero explains Tenantial governance model', async ({ page }) => {
await visitPage(page, '/platform');
await expectShell(page, /govern Microsoft tenants through evidence/i);
await expectPageFamily(page, 'landing');
await expectDisclosureLayer(page, '1');
await expectDisclosureLayer(page, '2');
await expectPrimaryNavigation(page);
await expectNavigationVsCtaDifferentiation(page);
await expectFooterLinks(page);
const main = page.getByRole('main');
await expect(main.locator('[data-hero-eyebrow]').first()).toContainText(/TENANTIAL PLATFORM/i);
await expect(page.getByRole('heading', { level: 1 })).toHaveCount(1);
await expect(page.getByRole('heading', { level: 1 })).toContainText(
/govern Microsoft tenants through evidence/i,
);
await expect(main.locator('[data-hero-supporting-copy]').first()).toContainText(/backup records/i);
await expect(main.locator('[data-hero-supporting-copy]').first()).toContainText(/configuration drift/i);
await expect(main.locator('[data-hero-supporting-copy]').first()).toContainText(/structured reviews/i);
await expectCtaHierarchy(page, 'Book a demo', 'See the governance loop');
await expect(main.locator('a[href="/contact"]').filter({ hasText: 'Book a demo' }).first()).toBeVisible();
await expect(main.locator('a[href="#governance-loop"]').filter({ hasText: 'See the governance loop' }).first()).toBeVisible();
await expect(main.locator('[data-platform-dashboard-preview]').first()).toBeVisible();
await expect(main.locator('[data-platform-dashboard-preview]').first()).toContainText(/Governance overview/i);
await expect(main.locator('[data-platform-dashboard-preview]').first()).toContainText(/Static demo preview/i);
await expect(main.locator('[data-platform-dashboard-preview]').first()).toContainText(/Evidence spotlight/i);
for (const signal of [
'Microsoft tenant focused',
'Evidence-oriented workflows',
'Reviewable decisions',
'Operator-led governance',
]) {
await expect(main.locator('[data-hero-trust-subclaims]').getByText(signal, { exact: true })).toBeVisible();
}
});
test('platform metadata is Tenantial clean', async ({ page }) => {
await visitPage(page, '/platform');
await expect(page).toHaveTitle(/Tenantial Platform/i);
await expect(page).toHaveTitle(/Evidence-first governance/i);
await expect(page.locator('meta[name="description"]')).toHaveAttribute('content', /backup/i);
await expect(page.locator('meta[name="description"]')).toHaveAttribute('content', /restore/i);
await expect(page.locator('meta[name="description"]')).toHaveAttribute('content', /drift detection/i);
await expect(page.locator('meta[name="description"]')).toHaveAttribute('content', /findings/i);
await expect(page.locator('meta[name="description"]')).toHaveAttribute('content', /evidence/i);
await expect(page.locator('meta[name="description"]')).toHaveAttribute('content', /audit trails/i);
await expect(page.locator('meta[name="description"]')).toHaveAttribute('content', /exceptions/i);
await expect(page.locator('meta[name="description"]')).toHaveAttribute('content', /reviews/i);
await expect(page.locator('link[rel="canonical"]')).toHaveAttribute('href', /\/platform$/);
await expectPlatformResidueAbsent(page);
});
test('platform governance flow explains reviewable evidence', async ({ page }) => {
await visitPage(page, '/platform');
const operatingModel = page.locator('[data-section="operating-model"]');
const governanceLoop = page.locator('[data-section="governance-loop"]');
await expect(operatingModel).toBeVisible();
await expect(operatingModel.locator('[data-operating-flow]')).toBeVisible();
for (const step of ['Snapshot', 'Drift', 'Finding', 'Review', 'Evidence', 'Audit trail']) {
await expect(operatingModel.getByText(step, { exact: true })).toBeVisible();
}
await expect(governanceLoop).toBeVisible();
await expect(governanceLoop.locator('[data-governance-loop-diagram]')).toBeVisible();
for (const label of [
'Source of truth',
'Snapshot',
'Diff',
'Finding',
'Exception',
'Review',
'Evidence',
'Audit trail',
]) {
await expect(governanceLoop.getByText(label, { exact: true })).toBeVisible();
}
await expect(governanceLoop).toContainText(/operator reviews/i);
await expect(governanceLoop).toContainText(/evidence/i);
await expect(governanceLoop).toContainText(/auditability/i);
});
test('platform governance flow avoids automation guarantees', async ({ page }) => {
await visitPage(page, '/platform');
await expect(page.locator('body')).not.toContainText(
/automatic remediation|guaranteed recovery|live device actions|real-time tenant operations/i,
);
});
test('platform capabilities cover governance primitives', async ({ page }) => {
await visitPage(page, '/platform');
const capabilities = page.locator('[data-section="platform-capabilities"]');
await expect(capabilities).toBeVisible();
await expect(capabilities.locator('[data-capability-system-grid]')).toBeVisible();
await expect(capabilities.locator('[data-capability-primary]')).toBeVisible();
await expect(capabilities.getByRole('heading', { name: 'Backup & Restore', exact: true })).toBeVisible();
for (const capability of [
'Drift Detection',
'Findings',
'Evidence',
'Audit Trail',
'Exceptions',
'Governance Reviews',
]) {
await expect(capabilities.getByRole('heading', { name: capability, exact: true })).toBeVisible();
}
});
test('platform boundaries keep claims conservative', async ({ page }) => {
await visitPage(page, '/platform');
const boundaries = page.locator('[data-section="platform-boundaries"]');
await expect(boundaries).toBeVisible();
await expect(boundaries).toContainText(/Built for governance of record/i);
await expect(boundaries).toContainText(/do not take actions on your behalf/i);
await expect(boundaries).toContainText(/do not manage devices/i);
await expect(boundaries).toContainText(/do not replace your ITSM/i);
await expect(boundaries).toContainText(/support reviewable decisions/i);
for (const claim of unsupportedPlatformClaims) {
await expect(page.locator('body')).not.toContainText(claim);
}
});
test.describe('platform mobile', () => {
test.use({ viewport: { width: 390, height: 844 } });
test('platform mobile layout stays readable without overflow', async ({ page }) => {
await visitPage(page, '/platform');
await expectMobileReadability(page);
await expectNoBodyHorizontalOverflow(page);
await expect(page.locator('[data-section="platform-capabilities"]').first()).toBeVisible();
await expect(page.locator('[data-section="platform-boundaries"]').first()).toBeVisible();
await expect(page.locator('[data-section="platform-capabilities"]').first()).toContainText(/Backup/i);
await expect(page.locator('[data-truth-layer-stack]').first()).toBeVisible();
await expect(page.locator('[data-governance-loop-diagram]').first()).toBeVisible();
await expect(page.locator('[data-section="platform-boundaries"]').first()).toContainText(/governance of record/i);
expect(await page.locator('[data-color-meaning="with-text"]').count()).toBeGreaterThan(0);
});
});
test('primary navigation and footer point Platform links to platform', async ({ page }) => {
await visitPage(page, '/platform');
await expectPrimaryNavigation(page);
await expectFooterLinks(page);
await expect(page.getByRole('contentinfo')).toHaveAttribute('data-footer-intent', 'quiet');
await expect(page.locator('[data-section="platform-final-cta"]')).toBeVisible();
await expect(page.getByRole('contentinfo')).not.toContainText(/Build tenant governance on evidence/i);
});
test('product redirects to platform', async ({ page }) => {
await expectCompatibilityRedirect(page, '/product', '/platform');
await expect(page.locator('body')).not.toContainText(
/AstroDeck|TemplateDeck|Open Source|MIT Licensed|TenantAtlas|TenantPilot|TenantCTRL/i,
);
});