選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. # Log Utility
  2. ## Principle
  3. Use structured logging that integrates with Playwright's test reports. Support object logging, test step decoration, and multiple log levels (info, step, success, warning, error, debug).
  4. ## Rationale
  5. Console.log in Playwright tests has limitations:
  6. - Not visible in HTML reports
  7. - No test step integration
  8. - No structured output
  9. - Lost in terminal noise during CI
  10. The `log` utility provides:
  11. - **Report integration**: Logs appear in Playwright HTML reports
  12. - **Test step decoration**: `log.step()` creates collapsible steps in UI
  13. - **Object logging**: Automatically formats objects/arrays
  14. - **Multiple levels**: info, step, success, warning, error, debug
  15. - **Optional console**: Can disable console output but keep report logs
  16. ## Quick Start
  17. ```typescript
  18. import { log } from '@seontechnologies/playwright-utils';
  19. // Basic logging
  20. await log.info('Starting test');
  21. await log.step('Test step shown in Playwright UI');
  22. await log.success('Operation completed');
  23. await log.warning('Something to note');
  24. await log.error('Something went wrong');
  25. await log.debug('Debug information');
  26. ```
  27. ## Pattern Examples
  28. ### Example 1: Basic Logging Levels
  29. **Context**: Log different types of messages throughout test execution.
  30. **Implementation**:
  31. ```typescript
  32. import { log } from '@seontechnologies/playwright-utils';
  33. test('logging demo', async ({ page }) => {
  34. await log.step('Navigate to login page');
  35. await page.goto('/login');
  36. await log.info('Entering credentials');
  37. await page.fill('#username', 'testuser');
  38. await log.success('Login successful');
  39. await log.warning('Rate limit approaching');
  40. await log.debug({ userId: '123', sessionId: 'abc' });
  41. // Errors still throw but get logged first
  42. try {
  43. await page.click('#nonexistent');
  44. } catch (error) {
  45. await log.error('Click failed', false); // false = no console output
  46. throw error;
  47. }
  48. });
  49. ```
  50. **Key Points**:
  51. - `step()` creates collapsible steps in Playwright UI
  52. - `info()`, `success()`, `warning()` for different message types
  53. - `debug()` for detailed data (objects/arrays)
  54. - `error()` with optional console suppression
  55. - All logs appear in test reports
  56. ### Example 2: Object and Array Logging
  57. **Context**: Log structured data for debugging without cluttering console.
  58. **Implementation**:
  59. ```typescript
  60. test('object logging', async ({ apiRequest }) => {
  61. const { body } = await apiRequest({
  62. method: 'GET',
  63. path: '/api/users',
  64. });
  65. // Log array of objects
  66. await log.debug(body); // Formatted as JSON in report
  67. // Log specific object
  68. await log.info({
  69. totalUsers: body.length,
  70. firstUser: body[0]?.name,
  71. timestamp: new Date().toISOString(),
  72. });
  73. // Complex nested structures
  74. await log.debug({
  75. request: {
  76. method: 'GET',
  77. path: '/api/users',
  78. timestamp: Date.now(),
  79. },
  80. response: {
  81. status: 200,
  82. body: body.slice(0, 3), // First 3 items
  83. },
  84. });
  85. });
  86. ```
  87. **Key Points**:
  88. - Objects auto-formatted as pretty JSON
  89. - Arrays handled gracefully
  90. - Nested structures supported
  91. - All visible in Playwright report attachments
  92. ### Example 3: Test Step Organization
  93. **Context**: Organize test execution into collapsible steps for better readability in reports.
  94. **Implementation**:
  95. ```typescript
  96. test('organized with steps', async ({ page, apiRequest }) => {
  97. await log.step('ARRANGE: Setup test data');
  98. const { body: user } = await apiRequest({
  99. method: 'POST',
  100. path: '/api/users',
  101. body: { name: 'Test User' },
  102. });
  103. await log.step('ACT: Perform user action');
  104. await page.goto(`/users/${user.id}`);
  105. await page.click('#edit');
  106. await page.fill('#name', 'Updated Name');
  107. await page.click('#save');
  108. await log.step('ASSERT: Verify changes');
  109. await expect(page.getByText('Updated Name')).toBeVisible();
  110. // In Playwright UI, each step is collapsible
  111. });
  112. ```
  113. **Key Points**:
  114. - `log.step()` creates collapsible sections
  115. - Organize by Arrange-Act-Assert
  116. - Steps visible in Playwright trace viewer
  117. - Better debugging when tests fail
  118. ### Example 4: Test Step Decorators
  119. **Context**: Create collapsible test steps in Playwright UI using decorators.
  120. **Page Object Methods with @methodTestStep:**
  121. ```typescript
  122. import { methodTestStep } from '@seontechnologies/playwright-utils';
  123. class TodoPage {
  124. constructor(private page: Page) {
  125. this.name = 'TodoPage';
  126. }
  127. readonly name: string;
  128. @methodTestStep('Add todo item')
  129. async addTodo(text: string) {
  130. await log.info(`Adding todo: ${text}`);
  131. const newTodo = this.page.getByPlaceholder('What needs to be done?');
  132. await newTodo.fill(text);
  133. await newTodo.press('Enter');
  134. await log.step('step within a decorator');
  135. await log.success(`Added todo: ${text}`);
  136. }
  137. @methodTestStep('Get all todos')
  138. async getTodos() {
  139. await log.info('Getting all todos');
  140. return this.page.getByTestId('todo-title');
  141. }
  142. }
  143. ```
  144. **Function Helpers with functionTestStep:**
  145. ```typescript
  146. import { functionTestStep } from '@seontechnologies/playwright-utils';
  147. // Define todo items for the test
  148. const TODO_ITEMS = ['buy groceries', 'pay bills', 'schedule meeting'];
  149. const createDefaultTodos = functionTestStep('Create default todos', async (page: Page) => {
  150. await log.info('Creating default todos');
  151. await log.step('step within a functionWrapper');
  152. const todoPage = new TodoPage(page);
  153. for (const item of TODO_ITEMS) {
  154. await todoPage.addTodo(item);
  155. }
  156. await log.success('Created all default todos');
  157. });
  158. const checkNumberOfTodosInLocalStorage = functionTestStep('Check total todos count fn-step', async (page: Page, expected: number) => {
  159. await log.info(`Verifying todo count: ${expected}`);
  160. const result = await page.waitForFunction((e) => JSON.parse(localStorage['react-todos']).length === e, expected);
  161. await log.success(`Verified todo count: ${expected}`);
  162. return result;
  163. });
  164. ```
  165. ### Example 5: File Logging
  166. **Context**: Enable file logging for persistent logs.
  167. **Implementation**:
  168. ```typescript
  169. // playwright/support/fixtures.ts
  170. import { test as base } from '@playwright/test';
  171. import { log, captureTestContext } from '@seontechnologies/playwright-utils';
  172. // Configure file logging globally
  173. log.configure({
  174. fileLogging: {
  175. enabled: true,
  176. outputDir: 'playwright-logs/organized-logs',
  177. forceConsolidated: false, // One file per test
  178. },
  179. });
  180. // Extend base test with file logging context capture
  181. export const test = base.extend({
  182. // Auto-capture test context for file logging
  183. autoTestContext: [
  184. async ({}, use, testInfo) => {
  185. captureTestContext(testInfo);
  186. await use(undefined);
  187. },
  188. { auto: true },
  189. ],
  190. });
  191. ```
  192. ### Example 6: Integration with Auth and API
  193. **Context**: Log authenticated API requests with tokens (safely).
  194. **Implementation**:
  195. ```typescript
  196. import { test } from '@seontechnologies/playwright-utils/fixtures';
  197. // Helper to create safe token preview
  198. function createTokenPreview(token: string): string {
  199. if (!token || token.length < 10) return '[invalid]';
  200. return `${token.slice(0, 6)}...${token.slice(-4)}`;
  201. }
  202. test('should log auth flow', async ({ authToken, apiRequest }) => {
  203. await log.info(`Using token: ${createTokenPreview(authToken)}`);
  204. await log.step('Fetch protected resource');
  205. const { status, body } = await apiRequest({
  206. method: 'GET',
  207. path: '/api/protected',
  208. headers: { Authorization: `Bearer ${authToken}` },
  209. });
  210. await log.debug({
  211. status,
  212. bodyPreview: {
  213. id: body.id,
  214. recordCount: body.data?.length,
  215. },
  216. });
  217. await log.success('Protected resource accessed successfully');
  218. });
  219. ```
  220. **Key Points**:
  221. - Never log full tokens (security risk)
  222. - Use preview functions for sensitive data
  223. - Combine with auth and API utilities
  224. - Log at appropriate detail level
  225. ## Configuration
  226. **Defaults:** console logging enabled, file logging disabled.
  227. ```typescript
  228. // Enable file logging in config
  229. log.configure({
  230. console: true, // default
  231. fileLogging: {
  232. enabled: true,
  233. outputDir: 'playwright-logs',
  234. forceConsolidated: false, // One file per test
  235. },
  236. });
  237. // Per-test override
  238. await log.info('Message', {
  239. console: { enabled: false },
  240. fileLogging: { enabled: true },
  241. });
  242. ```
  243. ### Environment Variables
  244. ```bash
  245. # Disable all logging
  246. SILENT=true
  247. # Disable only file logging
  248. DISABLE_FILE_LOGS=true
  249. # Disable only console logging
  250. DISABLE_CONSOLE_LOGS=true
  251. ```
  252. ### Level Filtering
  253. ```typescript
  254. log.configure({
  255. level: 'warning', // Only warning, error levels will show
  256. });
  257. // Available levels (in priority order):
  258. // debug < info < step < success < warning < error
  259. ```
  260. ### Sync Methods
  261. For non-test contexts (global setup, utility functions):
  262. ```typescript
  263. // Use sync methods when async/await isn't available
  264. log.infoSync('Initializing configuration');
  265. log.successSync('Environment configured');
  266. log.errorSync('Setup failed');
  267. ```
  268. ## Log Levels Guide
  269. | Level | When to Use | Shows in Report | Shows in Console |
  270. | --------- | ----------------------------------- | ----------------- | ---------------- |
  271. | `step` | Test organization, major actions | Collapsible steps | Yes |
  272. | `info` | General information, state changes | Yes | Yes |
  273. | `success` | Successful operations | Yes | Yes |
  274. | `warning` | Non-critical issues, skipped checks | Yes | Yes |
  275. | `error` | Failures, exceptions | Yes | Configurable |
  276. | `debug` | Detailed data, objects | Yes (attached) | Configurable |
  277. ## Comparison with console.log
  278. | console.log | log Utility |
  279. | ----------------------- | ------------------------- |
  280. | Not in reports | Appears in reports |
  281. | No test steps | Creates collapsible steps |
  282. | Manual JSON.stringify() | Auto-formats objects |
  283. | No log levels | 6 log levels |
  284. | Lost in CI output | Preserved in artifacts |
  285. ## Related Fragments
  286. - `overview.md` - Basic usage and imports
  287. - `api-request.md` - Log API requests
  288. - `auth-session.md` - Log auth flow (safely)
  289. - `recurse.md` - Log polling progress
  290. ## Anti-Patterns
  291. **DON'T log objects in steps:**
  292. ```typescript
  293. await log.step({ user: 'test', action: 'create' }); // Shows empty in UI
  294. ```
  295. **DO use strings for steps, objects for debug:**
  296. ```typescript
  297. await log.step('Creating user: test'); // Readable in UI
  298. await log.debug({ user: 'test', action: 'create' }); // Detailed data
  299. ```
  300. **DON'T log sensitive data:**
  301. ```typescript
  302. await log.info(`Password: ${password}`); // Security risk!
  303. await log.info(`Token: ${authToken}`); // Full token exposed!
  304. ```
  305. **DO use previews or omit sensitive data:**
  306. ```typescript
  307. await log.info('User authenticated successfully'); // No sensitive data
  308. await log.debug({ tokenPreview: token.slice(0, 6) + '...' });
  309. ```
  310. **DON'T log excessively in loops:**
  311. ```typescript
  312. for (const item of items) {
  313. await log.info(`Processing ${item.id}`); // 100 log entries!
  314. }
  315. ```
  316. **DO log summary or use debug level:**
  317. ```typescript
  318. await log.step(`Processing ${items.length} items`);
  319. await log.debug({ itemIds: items.map((i) => i.id) }); // One log entry
  320. ```