mirror of
				https://github.com/microsoft/playwright.git
				synced 2025-06-26 21:40:17 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			248 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			248 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
/**
 | 
						|
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 | 
						|
 *
 | 
						|
 * This source code is licensed under the MIT license found in the
 | 
						|
 * LICENSE file in the root directory of this source tree.
 | 
						|
 *
 | 
						|
 */
 | 
						|
 | 
						|
import { test, expect } from './fixtures';
 | 
						|
import { expect as expectUnderTest } from '../../packages/playwright/bundles/expect/src/expectBundleImpl';
 | 
						|
 | 
						|
expectUnderTest.extend({
 | 
						|
  toBeDivisibleBy(actual: number, expected: number) {
 | 
						|
    const pass = actual % expected === 0;
 | 
						|
    const message: () => string = pass
 | 
						|
      ? () =>
 | 
						|
        `expected ${this.utils.printReceived(
 | 
						|
            actual,
 | 
						|
        )} not to be divisible by ${expected}`
 | 
						|
      : () =>
 | 
						|
        `expected ${this.utils.printReceived(
 | 
						|
            actual,
 | 
						|
        )} to be divisible by ${expected}`;
 | 
						|
 | 
						|
    return { message, pass };
 | 
						|
  },
 | 
						|
  toBeSymbol(actual: symbol, expected: symbol) {
 | 
						|
    const pass = actual === expected;
 | 
						|
    const message = () =>
 | 
						|
      `expected ${actual.toString()} to be Symbol ${expected.toString()}`;
 | 
						|
 | 
						|
    return { message, pass };
 | 
						|
  },
 | 
						|
  toBeWithinRange(actual: number, floor: number, ceiling: number) {
 | 
						|
    const pass = actual >= floor && actual <= ceiling;
 | 
						|
    const message = pass
 | 
						|
      ? () =>
 | 
						|
        `expected ${this.utils.printReceived(
 | 
						|
            actual,
 | 
						|
        )} not to be within range ${floor} - ${ceiling}`
 | 
						|
      : () =>
 | 
						|
        `expected ${this.utils.printReceived(
 | 
						|
            actual,
 | 
						|
        )} to be within range ${floor} - ${ceiling}`;
 | 
						|
 | 
						|
    return { message, pass };
 | 
						|
  },
 | 
						|
});
 | 
						|
 | 
						|
const expectUnderTestAsAny = expectUnderTest as any;
 | 
						|
 | 
						|
test('is available globally when matcher is unary', () => {
 | 
						|
  expectUnderTestAsAny(15).toBeDivisibleBy(5);
 | 
						|
  expectUnderTestAsAny(15).toBeDivisibleBy(3);
 | 
						|
  expectUnderTestAsAny(15).not.toBeDivisibleBy(6);
 | 
						|
 | 
						|
  expect(() =>
 | 
						|
    expectUnderTestAsAny(15).toBeDivisibleBy(2),
 | 
						|
  ).toThrowErrorMatchingSnapshot(`expected <r>15</> to be divisible by 2`);
 | 
						|
});
 | 
						|
 | 
						|
test('is available globally when matcher is variadic', () => {
 | 
						|
  expectUnderTestAsAny(15).toBeWithinRange(10, 20);
 | 
						|
  expectUnderTestAsAny(15).not.toBeWithinRange(6, 10);
 | 
						|
 | 
						|
  expect(() =>
 | 
						|
    expectUnderTestAsAny(15).toBeWithinRange(1, 3),
 | 
						|
  ).toThrowErrorMatchingSnapshot(`expected <r>15</> to be within range 1 - 3`);
 | 
						|
});
 | 
						|
 | 
						|
test.skip('exposes matcherUtils in context', () => {
 | 
						|
  // expectUnderTest.extend({
 | 
						|
  //   shouldNotError(_actual: unknown) {
 | 
						|
  //     const pass: boolean = this.equals(
 | 
						|
  //         this.utils,
 | 
						|
  //         Object.assign(matcherUtils, {
 | 
						|
  //           iterableEquality,
 | 
						|
  //           subsetEquality,
 | 
						|
  //         }),
 | 
						|
  //     );
 | 
						|
  //     const message = pass
 | 
						|
  //       ? () => 'expected this.utils to be defined in an extend call'
 | 
						|
  //       : () => 'expected this.utils not to be defined in an extend call';
 | 
						|
 | 
						|
  //     return { message, pass };
 | 
						|
  //   },
 | 
						|
  // });
 | 
						|
 | 
						|
  // expectUnderTestAsAny('test').shouldNotError();
 | 
						|
});
 | 
						|
 | 
						|
test('is ok if there is no message specified', () => {
 | 
						|
  expectUnderTest.extend({
 | 
						|
    toFailWithoutMessage(_expected: unknown) {
 | 
						|
      return { message: () => '', pass: false };
 | 
						|
    },
 | 
						|
  });
 | 
						|
 | 
						|
  expect(() =>
 | 
						|
    expectUnderTestAsAny(true).toFailWithoutMessage(),
 | 
						|
  ).toThrowErrorMatchingSnapshot(`<r>No message was specified for this matcher.</>`);
 | 
						|
});
 | 
						|
 | 
						|
test('exposes an equality function to custom matchers', () => {
 | 
						|
  expectUnderTest.extend({
 | 
						|
    toBeOne(_expected: unknown) {
 | 
						|
      return { message: () => '', pass: !!this.equals(1, 1) };
 | 
						|
    },
 | 
						|
  });
 | 
						|
 | 
						|
  expect(() => expectUnderTestAsAny('test').toBeOne()).not.toThrow();
 | 
						|
});
 | 
						|
 | 
						|
test('defines asymmetric unary matchers', () => {
 | 
						|
  expect(() =>
 | 
						|
    expectUnderTest({ value: 2 }).toEqual({ value: expectUnderTestAsAny.toBeDivisibleBy(2) }),
 | 
						|
  ).not.toThrow();
 | 
						|
  expect(() =>
 | 
						|
    expectUnderTest({ value: 3 }).toEqual({ value: expectUnderTestAsAny.toBeDivisibleBy(2) }),
 | 
						|
  ).toThrowErrorMatchingSnapshot(`<d>expect(</><r>received</><d>).</>toEqual<d>(</><g>expected</><d>) // deep equality</>
 | 
						|
 | 
						|
<g>- Expected  - 1</>
 | 
						|
<r>+ Received  + 1</>
 | 
						|
 | 
						|
<d>  Object {</>
 | 
						|
<g>-   "value": toBeDivisibleBy<2>,</>
 | 
						|
<r>+   "value": 3,</>
 | 
						|
<d>  }</>`);
 | 
						|
});
 | 
						|
 | 
						|
test('defines asymmetric unary matchers that can be prefixed by not', () => {
 | 
						|
  expect(() =>
 | 
						|
    expectUnderTest({ value: 2 }).toEqual({ value: expectUnderTestAsAny.not.toBeDivisibleBy(2) }),
 | 
						|
  ).toThrowErrorMatchingSnapshot(`<d>expect(</><r>received</><d>).</>toEqual<d>(</><g>expected</><d>) // deep equality</>
 | 
						|
 | 
						|
<g>- Expected  - 1</>
 | 
						|
<r>+ Received  + 1</>
 | 
						|
 | 
						|
<d>  Object {</>
 | 
						|
<g>-   "value": not.toBeDivisibleBy<2>,</>
 | 
						|
<r>+   "value": 2,</>
 | 
						|
<d>  }</>`);
 | 
						|
  expect(() =>
 | 
						|
    expectUnderTest({ value: 3 }).toEqual({ value: expectUnderTestAsAny.not.toBeDivisibleBy(2) }),
 | 
						|
  ).not.toThrow();
 | 
						|
});
 | 
						|
 | 
						|
test('defines asymmetric variadic matchers', () => {
 | 
						|
  expect(() =>
 | 
						|
    expectUnderTest({ value: 2 }).toEqual({ value: expectUnderTestAsAny.toBeWithinRange(1, 3) }),
 | 
						|
  ).not.toThrow();
 | 
						|
  expect(() =>
 | 
						|
    expectUnderTest({ value: 3 }).toEqual({ value: expectUnderTestAsAny.toBeWithinRange(4, 11) }),
 | 
						|
  ).toThrowErrorMatchingSnapshot(`<d>expect(</><r>received</><d>).</>toEqual<d>(</><g>expected</><d>) // deep equality</>
 | 
						|
 | 
						|
<g>- Expected  - 1</>
 | 
						|
<r>+ Received  + 1</>
 | 
						|
 | 
						|
<d>  Object {</>
 | 
						|
<g>-   "value": toBeWithinRange<4, 11>,</>
 | 
						|
<r>+   "value": 3,</>
 | 
						|
<d>  }</>`);
 | 
						|
});
 | 
						|
 | 
						|
test('defines asymmetric variadic matchers that can be prefixed by not', () => {
 | 
						|
  expect(() =>
 | 
						|
    expectUnderTest({ value: 2 }).toEqual({
 | 
						|
      value: expectUnderTestAsAny.not.toBeWithinRange(1, 3),
 | 
						|
    }),
 | 
						|
  ).toThrowErrorMatchingSnapshot(`<d>expect(</><r>received</><d>).</>toEqual<d>(</><g>expected</><d>) // deep equality</>
 | 
						|
 | 
						|
<g>- Expected  - 1</>
 | 
						|
<r>+ Received  + 1</>
 | 
						|
 | 
						|
<d>  Object {</>
 | 
						|
<g>-   "value": not.toBeWithinRange<1, 3>,</>
 | 
						|
<r>+   "value": 2,</>
 | 
						|
<d>  }</>`);
 | 
						|
  expect(() =>
 | 
						|
    expectUnderTest({ value: 3 }).toEqual({
 | 
						|
      value: expectUnderTestAsAny.not.toBeWithinRange(5, 7),
 | 
						|
    }),
 | 
						|
  ).not.toThrow();
 | 
						|
});
 | 
						|
 | 
						|
test('prints the Symbol into the error message', () => {
 | 
						|
  const foo = Symbol('foo');
 | 
						|
  const bar = Symbol('bar');
 | 
						|
 | 
						|
  expect(() =>
 | 
						|
    expectUnderTest({ a: foo }).toEqual({
 | 
						|
      a: expectUnderTestAsAny.toBeSymbol(bar),
 | 
						|
    }),
 | 
						|
  ).toThrowErrorMatchingSnapshot(`<d>expect(</><r>received</><d>).</>toEqual<d>(</><g>expected</><d>) // deep equality</>
 | 
						|
 | 
						|
<g>- Expected  - 1</>
 | 
						|
<r>+ Received  + 1</>
 | 
						|
 | 
						|
<d>  Object {</>
 | 
						|
<g>-   "a": toBeSymbol<Symbol(bar)>,</>
 | 
						|
<r>+   "a": Symbol(foo),</>
 | 
						|
<d>  }</>`);
 | 
						|
});
 | 
						|
 | 
						|
test('allows overriding existing extension', () => {
 | 
						|
  expectUnderTest.extend({
 | 
						|
    toAllowOverridingExistingMatcher(_expected: unknown) {
 | 
						|
      return { message: () => '', pass: _expected === 'bar' };
 | 
						|
    },
 | 
						|
  });
 | 
						|
 | 
						|
  expectUnderTestAsAny('foo').not.toAllowOverridingExistingMatcher();
 | 
						|
 | 
						|
  expectUnderTest.extend({
 | 
						|
    toAllowOverridingExistingMatcher(_expected: unknown) {
 | 
						|
      return { message: () => '', pass: _expected === 'foo' };
 | 
						|
    },
 | 
						|
  });
 | 
						|
 | 
						|
  expectUnderTestAsAny('foo').toAllowOverridingExistingMatcher();
 | 
						|
});
 | 
						|
 | 
						|
test('throws descriptive errors for invalid matchers', () => {
 | 
						|
  expect(() =>
 | 
						|
    expectUnderTest.extend({
 | 
						|
      default: undefined,
 | 
						|
    }),
 | 
						|
  ).toThrow(
 | 
						|
      'expect.extend: `default` is not a valid matcher. Must be a function, is "undefined"',
 | 
						|
  );
 | 
						|
  expect(() =>
 | 
						|
    expectUnderTest.extend({
 | 
						|
      // @ts-expect-error: Testing runtime error
 | 
						|
      default: 42,
 | 
						|
    }),
 | 
						|
  ).toThrow(
 | 
						|
      'expect.extend: `default` is not a valid matcher. Must be a function, is "number"',
 | 
						|
  );
 | 
						|
  expect(() =>
 | 
						|
    expectUnderTest.extend({
 | 
						|
      // @ts-expect-error: Testing runtime error
 | 
						|
      default: 'foobar',
 | 
						|
    }),
 | 
						|
  ).toThrow(
 | 
						|
      'expect.extend: `default` is not a valid matcher. Must be a function, is "string"',
 | 
						|
  );
 | 
						|
});
 |