iT邦幫忙

2025 iThome 鐵人賽

DAY 28
1
Software Development

Playwright 玩家攻略:從新手村到魔王關系列 第 28

Day 28:VIP 通行證 (二)|藉由 storageState 實現秒速進入戰場:進階應用

  • 分享至 

  • xImage
  •  

上一篇運用 storageState() 成功從正常登入流程拿到驗證資料,並在後續的測試當中重複使用,如此就不必在每次的測試之前重複再走一遍登入流程。接著,要更進一步跳過登入流程,直接透過 API 拿到驗證資料,來看看如何實作吧!

Playwright 的 API 範例

先直接以 Playwright 官網的範例來試試看:

// setup/auth.setup.ts
import { test as setup } from '@playwright/test';

const authFile = 'playwright/.auth/user.json';

setup('authenticate', async ({ request }) => {
  // 傳送驗證請求,將 user 與 password 換成自己的
  await request.post('https://github.com/login', {
    form: {
      'user': 'user',
      'password': 'password'
    }
  });
  await request.storageState({ path: authFile });
});

執行之後順利拿到登入驗證的資料:
https://ithelp.ithome.com.tw/upload/images/20251007/20168913PokNv7ExYZ.png

看起來一切都是如此順利 ~ 如此簡單 ~

Automation Exercise 網站實作練習

那麼我們到 Automation Exercise 這個專門練習測試的網站試看看。

首先在網站上註冊一組帳號:

email: ada@example.com
password: ada001

查看此網站 API 列表,找到 POST To Verify Login with valid details 這一個 API:
https://ithelp.ithome.com.tw/upload/images/20251007/20168913wphdjgvQM1.png

將範例內容替換成剛剛註冊的帳號資訊:

import { test as setup } from '@playwright/test';

const exerciseAuthFile = 'playwright/.auth/exerciseUser.json';

setup('exercise authenticate', async ({ request }) => {
  await request.post('https://automationexercise.com/api/verifyLogin', {
    form: {
      'user': 'ada@example.com',
      'password': 'ada001'
    }
  });
  await request.storageState({ path: exerciseAuthFile });
});

滿心期待地按下執行!成功!
https://ithelp.ithome.com.tw/upload/images/20251007/201689134dkG5YB8OA.png

代誌不是憨人想得那麼簡單,Data 啥米都沒有...
https://ithelp.ithome.com.tw/upload/images/20251007/20168913k6JOP9c5V7.png

為了確認我們打 API 的過程是否正確,讓我們先到 Postman 嘗試看看:
https://ithelp.ithome.com.tw/upload/images/20251007/20168913CqpUWp9hOH.png

Postman 可以拿到預期的回傳資料,代表我們打 API 的過程沒有問題,那麼為什麼以 Playwright 的方法實作卻沒有拿到預期的回傳資料呢?先仔細檢查一下回傳資料:

setup('exercise authenticate', async ({ request }) => {
  // 發送認證請求,並儲存回應
  const response = await request.post('https://automationexercise.com/api/verifyLogin', {
    form: {
      'email': 'ada@example.com',
      'password': 'ada001'
    }
  });

  // 解析回應內容
  const responseBody = await response.json();
  console.log('API Response Content:', responseBody);

  await request.storageState({ path: exerciseAuthFile });
});

原來,預期的回應結果是儲存在 body 當中:
https://ithelp.ithome.com.tw/upload/images/20251007/20168913JSJxG9RYmr.png

若資料不存在 cookies,針對 API 回傳資料額外處理

再對照一下 Github 的範例,原來,Playwright 的 storageState() 方法會從 cookies 獲取驗證,但是,並非所有登入驗證的 API 都將資料儲存在 cookies 當中,如此,我們就必須對 API 回傳的資料額外處理。

不過由於剛剛的練習網站回傳內容並沒有驗證資料,我們改用其他同樣不是將驗證資料存在 cookies 的 API 嘗試看看:
https://ithelp.ithome.com.tw/upload/images/20251007/20168913G3LBqPBhxL.png

確認回傳的驗證 token 儲存在 Body 的 data 裡,就可以針對回傳內容做處理:

const url = 'baseUrl';
const account = 'ada001';
const password = 'password'

const apiAuthFile = path.join(__dirname, '../.auth/apiAuth.json');

setup('authenticate API', async ({ request }) => {
  // 傳送驗證請求
  const response = await request.post(`${url}/rpc/v4/sys/user/login`, {
    form: {
      "client_type": 'webx',
      'account': account,
      'password': password
    }
  });

  console.log('API Response status:', response.status());

  // 解析回應獲取 token
  const responseBody = await response.json();
  console.log('Login successful, received token');

  if (responseBody.status && responseBody.data && responseBody.data.token) {
    const token = responseBody.data.token;
    console.log('Token received:', token.substring(0, 50) + '...');

    // 創建包含 JWT token 的認證資訊
    const authData = {
      token: token,
      cookies: [{ value: token }],
      // 添加額外的認證資訊
      extraHTTPHeaders: {
        'Authorization': `Bearer ${token}`,
        'X-Auth-Token': token
      }
    };

    // 手動保存認證資料
    const fs = require('fs');
    const path = require('path');

    // 確保 .auth 資料夾存在
    const authDir = path.dirname(apiAuthFile);
    if (!fs.existsSync(authDir)) {
      fs.mkdirSync(authDir, { recursive: true });
    }

    // 保存 token 資料
    fs.writeFileSync(apiAuthFile, JSON.stringify(authData, null, 2));
    console.log('Auth data saved to:', apiAuthFile);

    // 驗證保存的內容
    const savedContent = fs.readFileSync(apiAuthFile, 'utf8');
    console.log('Saved auth data preview:', savedContent.substring(0, 200) + '...');

  } else {
    throw new Error('Failed to get token from API response');
  }
});

執行測試時,就能看見登入的驗證資料實際被儲存起來:
https://ithelp.ithome.com.tw/upload/images/20251007/20168913NaxgjVXmkH.png


到這裡,我們嘗試透過 API 取得驗證資料並以 storageState() 將其儲存起來,接下來,我們要試圖將這個流程整合進 POM (Page Object Model) 架構中,讓測試能夠靈活地以不同角色登入,實現更具擴充性的驗證流程。


上一篇
Day 27:VIP 通行證 (一)|藉由 storageState() 實現秒速進入戰場:基礎應用
下一篇
Day 29:VIP 通行證 (三)|藉由 storageState 實現秒速進入戰場:多角色應用
系列文
Playwright 玩家攻略:從新手村到魔王關29
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言