У меня есть следующая функция:
export default function main() {
const createAndAppendPTag = () => {
const p = document.createElement('p');
document.body.appendChild(p);
};
window.document.addEventListener('click', () => {
createAndAppendPTag();
});
}
Вопрос в том, как я могу утверждать с помощью Jest, что createAndAppendPTag
вызывается при событии щелчка по документу?
Это то, что я пробовал, но не могу пройти тест:
import main from './main'
window.document.addEventListener = jest.fn();
const createAndAppendPTag = jest.fn();
describe('Main', () => {
const documentClickEvent = new Event('click');
test('appends p tag to the document', () => {
// dispatching event before and after invoking `main` to be sure
window.document.dispatchEvent(documentClickEvent);
main();
window.document.dispatchEvent(documentClickEvent);
expect(window.document.addEventListener).toHaveBeenNthCalledWith(1, 'click', () => {});
expect(createAndAppendPTag).toHaveBeenCalledTimes(1);
});
});
Это приводит к следующему:
🔴 Main › appends p tag to the document
expect(jest.fn()).toHaveBeenNthCalledWith(n, ...expected)
n: 1
Expected: "click", [Function anonymous]
Number of calls: 0
5 | main();
6 | window.document.dispatchEvent(documentClickEvent);
> 7 | expect(window.document.addEventListener).toHaveBeenNthCalledWith(1, 'click', () => {});
* | ^
Заранее спасибо.
Спасибо за предложение @terrymorse, я пытался сделать это в течение последнего часа или около того, но безуспешно, кажется, мне нужно позже задать еще один вопрос о запросе домена в тесте, потому что я получаю пустое тело, до тех пор возможно, кто-то может предоставить другое предложение/решение.
Вы можете использовать jest.spyOn(object, methodName) для создания макетов для методов window.document.addEventListener()
, document.createElement()
и document.body.appendChild()
.
Поскольку функция createAndAppendPTag
является приватной, вы не можете шпионить/издеваться над ней, но вы можете косвенно определить, вызывается ли она, утверждая ее внутренний метод.
Например. используя "jest": "^26.6.3"
:
main.js
:
export default function main() {
const createAndAppendPTag = () => {
const p = document.createElement('p');
document.body.appendChild(p);
};
window.document.addEventListener('click', () => {
createAndAppendPTag();
});
}
main.test.js
:
import main from './main';
describe('65451115', () => {
afterAll(() => {
jest.restoreAllMocks();
});
it('should pass', () => {
const createElementSpy = jest.spyOn(document, 'createElement').mockReturnValue('fake p');
const appendChildSpy = jest.spyOn(document.body, 'appendChild').mockReturnValue();
const addEventListenerSpy = jest
.spyOn(window.document, 'addEventListener')
.mockImplementationOnce((event, handler) => {
handler();
});
main();
expect(addEventListenerSpy).toBeCalledWith('click', expect.any(Function));
expect(createElementSpy).toBeCalledWith('p');
expect(appendChildSpy).toBeCalledWith('fake p');
});
});
результат модульного теста:
PASS examples/65451115/main.test.js (10.621 s)
65451115
✓ should pass (4 ms)
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
main.js | 100 | 100 | 100 | 100 |
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 16.536 s
Спасибо за идею! Есть ли шанс, что я могу утверждать, что createAndAppendPTag
был вызван? (даже если мне придется изменить исходный код)
@SamLahm Вам нужно разоблачить его, чтобы вы могли установить шпиона или издеваться над ним. Тогда вы можете утверждать, что это было вызвано или нет.
Я провел этот упрощенный тест, чтобы проверить наличие побочного эффекта (элемент p
был добавлен к телу):
main.js
export default function main() {
const createAndAppendPTag = () => {
const p = document.createElement('p');
document.body.appendChild(p);
};
window.document.addEventListener('click', () => {
createAndAppendPTag();
});
}
main.test.js
import main from `../main.js`;
it('"main" listener appends "P" to body upon click', () => {
// add listener
main();
// clear body contents
document.body.innerHTML = "";
// dispatch click event to listener
const addEvt = new Event('click');
document.dispatchEvent(addEvt);
// check for existence of "P" element
const bodyEl = document.body.firstChild;
expect(bodyEl).not.toEqual(null);
expect(bodyEl.tagName).toBe('P');
document.body.innerHTML = "";
});
Прошло:
✓ "main" listener appends "P" to body upon click (2 ms)
Спасибо, Терри, как вы предложили, я должен утверждать побочный эффект в таких случаях. Отметить это как правильный ответ (просто typeof bodyEl
не требуется, так как все в JS является объектом: D)
@SamLahm Ну, не все в JS является объектом. Есть string
, number
, boolean
и undefined
, и это лишь некоторые из них. Хотя null
— это объект, что является проблемой. Так что этот тест лучше: expect(bodyEl).not.toEqual(null)
(ответ изменю).
createAndAppendPTag
является приватным для основного, поэтому вы не видите его во время тестирования. Можете ли вы просто проверить побочный эффект напрямую (p
был добавлен в тело)?