Files
pezkuwi-dev/packages/dev-test/src/env/expect.spec.ts
T
Satoshi Qazi Muhammed 4e3bf04010 dev-test: DOM node hierarchy in the browser env; expect().toContain
The browser env exposed the HTML*Element constructors but not the
classes above them, so a library checking `instanceof Element` (as
react-tooltip does on every hover) threw "Element is not defined".
Node, Element, Document, DocumentFragment, Text, ShadowRoot and
SVGElement now come from JSDOM.

expect().toContain and .not.toContain were stubs. A string contains a
substring; any other iterable contains the item itself, not a
deep-equal copy, as in jest.
2026-10-10 08:56:58 +04:00

283 lines
7.6 KiB
TypeScript

// Copyright 2017-2026 @pezkuwi/dev-test authors & contributors
// SPDX-License-Identifier: Apache-2.0
describe('expect', () => {
it('has been decorated', () => {
expect(expect(true).not).toBeDefined();
});
it('throws on unimplemented', () => {
expect(
() => expect(true).not.toHaveReturnedWith()
).toThrow('expect(...).not.toHaveReturnedWith has not been implemented');
});
it('throws on unimplemented (with alternative)', () => {
expect(
() => expect(true).not.toBeFalsy()
).toThrow('expect(...).not.toBeFalsy has not been implemented (Use expect(...).toBeTruthy instead)');
});
describe('rejects', () => {
it('matches a rejection via .toThrow', async () => {
await expect(
Promise.reject(new Error('this is a rejection message'))
).rejects.toThrow(/rejection/);
});
});
describe('.toBeDefined', () => {
it('does not throw on null', () => {
expect(null).toBeDefined();
});
it('throws on undefined', () => {
expect(
() => expect(undefined).toBeDefined()
).toThrow();
});
it('.not does not throw on undefined', () => {
expect(undefined).not.toBeDefined();
});
});
describe('.toThrow', () => {
const thrower = () => {
throw new Error('some error');
};
it('matches error with empty throw', () => {
expect(thrower).toThrow();
});
it('matches error with exact message', () => {
expect(thrower).toThrow('some error');
});
it('matches error with regex message', () => {
expect(thrower).toThrow(/me er/);
});
it('handles .not correctly (no throw, empty message)', () => {
expect(() => undefined).not.toThrow();
});
it('handles .not correctly (no throw, regex match)', () => {
expect(() => undefined).not.toThrow(/me er/);
});
it('handles .not correctly (throw, string match)', () => {
expect(() => undefined).not.toThrow('no match');
});
it('handles .not correctly (throw, regex match)', () => {
expect(() => undefined).not.toThrow(/no match/);
});
});
describe('.toMatch', () => {
it('fails matching when non-object passed in', () => {
expect(
() => expect(undefined).toMatch(/match/)
).toThrow(/Expected string/);
});
it('fails matching when non-matching string passed in', () => {
expect(
() => expect('some').toMatch(/match/)
).toThrow(/did not match/);
});
it('matches string passed', () => {
expect(
() => expect('matching').toMatch(/match/)
).not.toThrow();
});
});
describe('.toMatchObject', () => {
it('fails matching when non-object passed in', () => {
expect(
() => expect(undefined).toMatchObject({ foo: 'bar' })
).toThrow(/Expected object/);
});
it('matches empty object', () => {
expect({
a: 'foo',
b: 'bar'
}).toMatchObject({});
});
it('matches object with some fields', () => {
expect({
a: 'foo',
b: 'bar',
c: 123,
d: [456, 789]
}).toMatchObject({
a: 'foo',
c: 123,
d: [456, 789]
});
});
it('matches an object with some expect.stringMatching supplied', () => {
expect({
a: 'foo bar',
b: 'baz',
c: 'zaz'
}).toMatchObject({
a: expect.stringMatching(/o b/),
b: expect.stringMatching('baz'),
c: 'zaz'
});
});
it('matches an object with expect.any supplied', () => {
expect({
a: 123,
b: Boolean(true),
c: 'foo'
}).toMatchObject({
a: expect.any(Number),
b: expect.any(Boolean),
c: 'foo'
});
});
it('does not match an object with non instance value for expect.any', () => {
expect(
() => expect({
a: true,
b: 'foo'
}).toMatchObject({
a: expect.any(Number),
b: 'foo'
})
).toThrow(/not an instance of Number/);
});
it('matches an object with expect.anything supplied', () => {
expect({
a: 123,
b: 'foo'
}).toMatchObject({
a: expect.anything(),
b: 'foo'
});
});
it('does not match an object with undefined value for expect.anything', () => {
expect(
() => expect({
b: 'foo'
}).toMatchObject({
a: expect.anything(),
b: 'foo'
})
).toThrow(/non-nullish/);
});
it('does not match an object with non-array value', () => {
expect(
() => expect({
a: 'foo',
b: 'bar'
}).toMatchObject({
a: 'foo',
b: [123, 456]
})
).toThrow(/Expected array value/);
});
it('allows for deep matching', () => {
expect({
a: 123,
b: {
c: 456,
d: {
e: 'foo',
f: 'bar',
g: {
h: [789, { z: 'baz' }]
}
}
}
}).toMatchObject({
a: 123,
b: {
c: expect.any(Number),
d: {
f: 'bar',
g: {
h: [expect.any(Number), { z: 'baz' }]
}
}
}
});
});
});
describe('asymmetric matchers in .toEqual', () => {
it('matches an array containing all expected entries, in any order', () => {
expect([1, 2, 3]).toEqual(expect.arrayContaining([3, 1]));
expect(['a', 'b']).toEqual(expect.arrayContaining(['b', 'a']));
});
it('fails when an expected entry is missing', () => {
expect(() => expect([1, 2]).toEqual(expect.arrayContaining([3]))).toThrow();
});
it('compares array entries deeply', () => {
expect([{ a: 1 }, { b: 2 }]).toEqual(expect.arrayContaining([{ b: 2 }]));
expect(() => expect([{ a: 1 }]).toEqual(expect.arrayContaining([{ a: 2 }]))).toThrow();
});
it('matches a string containing the expected part', () => {
expect('hello world').toEqual(expect.stringContaining('lo w'));
expect(() => expect('hello').toEqual(expect.stringContaining('xyz'))).toThrow();
});
it('applies matchers nested in objects and arrays', () => {
expect({ a: [1, 2], b: 'x' }).toEqual({ a: expect.arrayContaining([2]), b: 'x' });
expect([{ a: 'xyz' }]).toEqual([{ a: expect.stringContaining('y') }]);
expect(() => expect({ a: [1], b: 'x' }).toEqual({ a: expect.arrayContaining([2]), b: 'x' })).toThrow();
});
it('still requires equal keys around a nested matcher', () => {
expect(() => expect({ a: [1], b: 'x', c: 1 }).toEqual({ a: expect.arrayContaining([1]), b: 'x' })).toThrow();
});
it('supports .not with a matcher', () => {
expect([1, 2]).not.toEqual(expect.arrayContaining([3]));
expect(() => expect([1, 2]).not.toEqual(expect.arrayContaining([2]))).toThrow();
});
});
describe('.toContain', () => {
it('finds a substring in a string', () => {
expect('voter-alice').toContain('alice');
expect(() => expect('voter-alice').toContain('bob')).toThrow();
});
it('finds the item itself in an array or other iterable', () => {
const item = { a: 1 };
expect([1, item]).toContain(item);
expect(new Set(['a'])).toContain('a');
expect(() => expect([{ a: 1 }]).toContain({ a: 1 })).toThrow();
});
it('rejects a value that is neither a string nor an iterable', () => {
expect(() => expect(123).toContain(1)).toThrow();
});
it('supports .not', () => {
expect('voter-alice').not.toContain('bob');
expect(() => expect([1, 2]).not.toContain(2)).toThrow();
});
});
});