我要添加两个单元测试,以涵盖选择器是否在页面上的情况。
async function getPrice(page, url) {
const priceSelector = '#price';
if (await page.$(priceSelector)) {
return page.$eval(priceSelector, elem => elem.innerText);
}
return null;
}
page
在另一个函数中定义:
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto(url);
我尝试模拟page
,以使page.$(priceSelector)
返回真实或错误,但没有成功。 doc中的模拟模块示例很有意义,但实际上我的代码是否可以测试?如果没有,应该如何构造?
答案 0 :(得分:1)
只需重构一个位置,最好将回调函数elem => elem.innerText
提取到一个新函数中。
例如
index.ts
:
export async function getPrice(page, url) {
const priceSelector = '#price';
if (await page.$(priceSelector)) {
return page.$eval(priceSelector, elem => elem.innerText);
}
return null;
}
index.spec.ts
:
import { getPrice } from './';
const page = {
$: jest.fn(),
$eval: jest.fn()
};
beforeEach(() => {
jest.resetAllMocks();
});
test('should eval', async () => {
page.$.mockResolvedValueOnce(true);
page.$eval.mockReturnValueOnce('dummy data');
const actualValue = await getPrice(page, 'example.com');
expect(actualValue).toBe('dummy data');
expect(page.$).toBeCalledWith('#price');
expect(page.$eval).toBeCalledWith('#price', expect.any(Function));
});
test('should return null', async () => {
page.$.mockResolvedValueOnce(false);
const actualValue = await getPrice(page, 'example.com');
expect(actualValue).toBeNull();
expect(page.$).toBeCalledWith('#price');
expect(page.$eval).not.toBeCalled();
});
您可以像这样测试它,但是回调函数将不会被测试和覆盖。
带有覆盖率报告的单元测试结果:
PASS src/stackoverflow/58651192/index.spec.ts
✓ should eval (6ms)
✓ should return null (2ms)
----------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
----------|----------|----------|----------|----------|-------------------|
All files | 85.71 | 100 | 50 | 100 | |
index.ts | 85.71 | 100 | 50 | 100 | |
----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 4.786s, estimated 7s
如果我们像这样提取$eval
的回调函数:
export const evalCallback = elem => elem.innerText;
我们可以轻松对其进行测试:
test('evalCallback', () => {
const actualValue = evalCallback({ innerText: 'unit test' });
expect(actualValue).toBe('unit test');
});
覆盖率100%的单元测试结果:
PASS src/stackoverflow/58651192/index.spec.ts (9.066s)
✓ should eval (10ms)
✓ should return null (1ms)
✓ evalCallback (1ms)
----------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
----------|----------|----------|----------|----------|-------------------|
All files | 100 | 100 | 100 | 100 | |
index.ts | 100 | 100 | 100 | 100 | |
----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests: 3 passed, 3 total
Snapshots: 0 total
Time: 10.804s