fix: update action versions in Nix build workflow (#78)

This commit is contained in:
Asep Haryana Saputra
2026-04-13 14:28:10 +07:00
committed by GitHub
parent 06c69cb3c5
commit 426b71f341
35 changed files with 2613 additions and 445 deletions
+141
View File
@@ -0,0 +1,141 @@
import { test, expect } from '@playwright/test';
import fs from 'fs';
import path from 'path';
/**
* Test configuration for dashboard screenshot capture
*/
interface DashboardTestCase {
persona: 'user' | 'mentor';
viewport: 'desktop' | 'mobile';
roleName: string;
waitForText: string;
screenshotFileName: string;
}
/**
* Mock authentication token structure
*/
const mockToken = {
access_token: 'mock_access_token_' + Math.random().toString(36).substring(7),
refresh_token: 'mock_refresh_token_' + Math.random().toString(36).substring(7),
};
/**
* Create a mock user object based on persona
*/
function createMockUser(persona: 'user' | 'mentor') {
const basUser = {
id: 'mock-user-id',
email: 'test@imphnen.com',
fullname: 'Test User',
is_active: true,
role: {
id: 'role-' + persona,
name: persona === 'mentor' ? 'Mentor Role' : 'User Role',
permissions: [],
},
};
return basUser;
}
/**
* Dashboard test cases
*/
const testCases: DashboardTestCase[] = [
{
persona: 'user',
viewport: 'desktop',
roleName: 'User Role',
waitForText: 'Roadmaps',
screenshotFileName: 'dashboard_user_mock_desktop.png',
},
{
persona: 'mentor',
viewport: 'desktop',
roleName: 'Mentor Role',
waitForText: 'Analytics',
screenshotFileName: 'dashboard_mentor_mock_desktop.png',
},
{
persona: 'user',
viewport: 'mobile',
roleName: 'User Role',
waitForText: 'Roadmaps',
screenshotFileName: 'dashboard_user_mock_mobile.png',
},
{
persona: 'mentor',
viewport: 'mobile',
roleName: 'Mentor Role',
waitForText: 'Analytics',
screenshotFileName: 'dashboard_mentor_mock_mobile.png',
},
];
test.describe('Dashboard Screenshot Capture', () => {
const screenshotDir = path.resolve(__dirname, '../screenshots');
test.beforeAll(() => {
if (!fs.existsSync(screenshotDir)) {
fs.mkdirSync(screenshotDir, { recursive: true });
}
});
/**
* Run test for each dashboard variant
*/
for (const testCase of testCases) {
test(`capture ${testCase.persona} ${testCase.viewport} dashboard screenshot`, async ({
page,
context,
}) => {
// Set viewport size based on device type
const viewportSize = testCase.viewport === 'desktop' ? { width: 1280, height: 832 } : { width: 375, height: 667 };
await page.setViewportSize(viewportSize);
// Set authentication cookie with mock token
const tokenCookie = {
name: 'token',
value: JSON.stringify({ token: mockToken }),
url: 'http://localhost:3000',
secure: false,
httpOnly: false,
sameSite: 'Strict' as const,
};
await context.addCookies([tokenCookie]);
// Set user in localStorage
const mockUser = createMockUser(testCase.persona);
await page.goto('http://localhost:3000', { waitUntil: 'domcontentloaded' });
await page.evaluate(
({ user }) => {
localStorage.setItem('users', JSON.stringify(user));
},
{ user: mockUser }
);
// Navigate to dashboard with persona parameter for explicit override
const dashboardUrl = `http://localhost:3000/dashboard?persona=${testCase.persona}`;
await page.goto(dashboardUrl, { waitUntil: 'networkidle', timeout: 30000 });
// Wait for stable dashboard content
await page.waitForSelector(
`text="${testCase.waitForText}"`,
{ timeout: 10000 }
);
// Additional wait for content to render
await page.waitForTimeout(1000);
// Capture screenshot
const screenshotPath = path.join(screenshotDir, testCase.screenshotFileName);
await page.screenshot({
path: screenshotPath,
fullPage: true,
});
console.log(`✓ Captured: ${testCase.screenshotFileName}`);
});
}
});
+83
View File
@@ -0,0 +1,83 @@
import { test, expect } from '@playwright/test';
import fs from 'fs';
import path from 'path';
/**
* Dynamically extract all routes from the TanStack Router generated file.
*/
function getDynamicRoutes(): string[] {
const routeTreePath = path.resolve(__dirname, '../src/routeTree.gen.ts');
if (!fs.existsSync(routeTreePath)) {
console.warn('Route tree file not found, falling back to basic routes');
return ['/'];
}
const content = fs.readFileSync(routeTreePath, 'utf-8');
// Extract the FileRoutesByFullPath interface block
const interfaceMatch = content.match(/export interface FileRoutesByFullPath \{([\s\S]*?)\}/);
if (!interfaceMatch) return ['/'];
const block = interfaceMatch[1];
// Extract all strings in single quotes
const routeMatches = block.match(/'([^']+)'/g);
if (!routeMatches) return ['/'];
return routeMatches.map(m => {
let route = m.replace(/'/g, '');
// Normalize trailing slashes (Optional cleanup)
if (route !== '/' && route.endsWith('/')) {
route = route.slice(0, -1);
}
// Replace dynamic parameters with sample values
return route
.replace(/\$slug/g, 'sample-article')
.replace(/\$id/g, 'sample-id')
.replace(/\$taskId/g, 'sample-task');
});
}
test.describe('Automated Route Discovery & Screenshots', () => {
const baseURL = process.env.BASE_URL || 'http://localhost:3000';
const screenshotDir = path.resolve(__dirname, '../screenshots');
const routes = [...new Set(getDynamicRoutes())]; // Unique routes
test.beforeAll(() => {
if (!fs.existsSync(screenshotDir)) {
fs.mkdirSync(screenshotDir, { recursive: true });
}
});
console.log(`Discovered ${routes.length} routes for processing.`);
for (const route of routes) {
test(`capture screenshot: ${route}`, async ({ page }) => {
console.log(`Processing: ${baseURL}${route}`);
try {
await page.goto(`${baseURL}${route}`, {
waitUntil: 'networkidle',
timeout: 30000
});
// Wait for rendering
await page.waitForTimeout(1500);
const fileName = route.replace(/\//g, '_').replace(/^_/, '').replace(/[:$]/g, '') || 'home';
const screenshotPath = path.join(screenshotDir, `${fileName}.png`);
await page.screenshot({
path: screenshotPath,
fullPage: true
});
console.log(`Success: ${fileName}.png`);
} catch (error) {
console.error(`Failed to capture ${route}:`, error.message);
}
});
}
});