diff --git a/package.json b/package.json index c06fd0497..01b78a9db 100644 --- a/package.json +++ b/package.json @@ -82,6 +82,7 @@ "flow": "flow", "copy-flowtypes": "cp typings/index.flow.js build", "lint": "eslint src --cache", + "validate": "yarn lint && yarn typecheck && yarn test", "prepublish": "yarn build", "build:js": "babel src --out-dir build --extensions \".js,.ts,.jsx,.tsx\" --source-maps --ignore \"**/__tests__/**\"", "build:js:watch": "yarn build:js --watch", diff --git a/src/matchers/__tests__/to-have-style.test.tsx b/src/matchers/__tests__/to-have-style.test.tsx new file mode 100644 index 000000000..46834cccd --- /dev/null +++ b/src/matchers/__tests__/to-have-style.test.tsx @@ -0,0 +1,175 @@ +import React from 'react'; +import { StyleSheet, View, Pressable } from 'react-native'; +import { render } from '../..'; +import '../extend-expect'; + +const styles = StyleSheet.create({ + container: { borderBottomColor: 'white' }, +}); + +test('toHaveStyle() handles basic cases', () => { + const screen = render( + + ); + + const view = screen.getByTestId('view'); + expect(view).toHaveStyle({ backgroundColor: 'blue' }); + expect(view).toHaveStyle({ height: '100%' }); + expect(view).toHaveStyle({ backgroundColor: 'blue', height: '100%' }); + expect(view).toHaveStyle([{ backgroundColor: 'blue' }, { height: '100%' }]); + + expect(view).toHaveStyle({ borderBottomColor: 'white' }); + expect(view).toHaveStyle({ width: '50%' }); + expect(view).toHaveStyle([[{ width: '50%' }]]); + expect(view).toHaveStyle({ + transform: [{ scale: 2 }, { rotate: '45deg' }], + }); + + expect(view).not.toHaveStyle({ backgroundColor: 'red' }); + expect(view).not.toHaveStyle({ height: '50%' }); + expect(view).not.toHaveStyle({ backgroundColor: 'blue', height: '50%' }); + expect(view).not.toHaveStyle([ + { backgroundColor: 'blue' }, + { height: '50%' }, + ]); + expect(view).not.toHaveStyle({ + transform: [{ scale: 2 }], + }); + expect(view).not.toHaveStyle({ + transform: [{ rotate: '45deg' }, { scale: 2 }], + }); +}); + +test('toHaveStyle error messages', () => { + const screen = render( + + ); + + const view = screen.getByTestId('view'); + expect(() => expect(view).toHaveStyle({ backgroundColor: 'red' })) + .toThrowErrorMatchingInlineSnapshot(` + "expect(element).toHaveStyle() + + - Expected + + Received + + - backgroundColor: red; + + backgroundColor: blue;" + `); + + expect(() => + expect(view).toHaveStyle({ + backgroundColor: 'blue', + transform: [{ scale: 1 }], + }) + ).toThrowErrorMatchingInlineSnapshot(` + "expect(element).toHaveStyle() + + - Expected + + Received + + backgroundColor: blue; + transform: [ + { + - "scale": 1 + + "scale": 2 + + }, + + { + + "rotate": "45deg" + } + ];" + `); + + expect(() => expect(view).not.toHaveStyle({ backgroundColor: 'blue' })) + .toThrowErrorMatchingInlineSnapshot(` + "expect(element).not.toHaveStyle() + + Expected element not to have style: + backgroundColor: blue; + Received: + backgroundColor: blue;" + `); + + expect(() => expect(view).toHaveStyle({ fontWeight: 'bold' })) + .toThrowErrorMatchingInlineSnapshot(` + "expect(element).toHaveStyle() + + - Expected + + Received + + - fontWeight: bold;" + `); + + expect(() => expect(view).not.toHaveStyle({ backgroundColor: 'blue' })) + .toThrowErrorMatchingInlineSnapshot(` + "expect(element).not.toHaveStyle() + + Expected element not to have style: + backgroundColor: blue; + Received: + backgroundColor: blue;" + `); +}); + +test('toHaveStyle() supports missing "style" prop', () => { + const screen = render(); + + const view = screen.getByTestId('view'); + expect(view).not.toHaveStyle({ fontWeight: 'bold' }); +}); + +test('toHaveStyle() supports undefined "transform" style', () => { + const screen = render( + + ); + + const view = screen.getByTestId('view'); + expect(() => expect(view).toHaveStyle({ transform: [{ scale: 1 }] })) + .toThrowErrorMatchingInlineSnapshot(` + "expect(element).toHaveStyle() + + - Expected + + Received + + - transform: [ + - { + - "scale": 1 + - } + - ]; + + transform: undefined;" + `); +}); + +test('toHaveStyle() supports Pressable with function "style" prop', () => { + const screen = render( + ({ backgroundColor: 'blue' })} /> + ); + + expect(screen.getByTestId('view')).toHaveStyle({ backgroundColor: 'blue' }); +}); diff --git a/src/matchers/extend-expect.d.ts b/src/matchers/extend-expect.d.ts index acdb16d1d..54e02213c 100644 --- a/src/matchers/extend-expect.d.ts +++ b/src/matchers/extend-expect.d.ts @@ -1,4 +1,6 @@ +import type { StyleProp } from 'react-native'; import type { TextMatch, TextMatchOptions } from '../matches'; +import type { Style } from './to-have-style'; export interface JestNativeMatchers { toBeOnTheScreen(): R; @@ -12,6 +14,7 @@ export interface JestNativeMatchers { toBeVisible(): R; toHaveDisplayValue(expectedValue: TextMatch, options?: TextMatchOptions): R; toHaveProp(name: string, expectedValue?: unknown): R; + toHaveStyle(style: StyleProp