feat: add component tests using react-testing-library and jest (#14331)

This commit is contained in:
Jamie Caprani 2022-11-23 13:59:18 +00:00 committed by GitHub
parent bab0fc7ac0
commit c6e8aad745
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 2470 additions and 890 deletions

View File

@ -1,8 +0,0 @@
{
"presets": [
"module:metro-react-native-babel-preset"
],
"plugins": [
"react-native-reanimated/plugin"
]
}

1
.gitignore vendored
View File

@ -7,6 +7,7 @@
# Xcode
#
/component-spec
result/
build/
*.pbxuser

View File

@ -307,7 +307,7 @@ test-watch: ##@ Watch tests and re-run no changes to cljs files
test: export TARGET := clojure
test: ##@test Run tests once in NodeJS
# Here we creates the gyp bindings for nodejs
# Here we create the gyp bindings for nodejs
yarn install
yarn shadow-cljs compile mocks && \
yarn shadow-cljs compile test && \
@ -316,14 +316,27 @@ test: ##@test Run tests once in NodeJS
run-visual-test-ios: export TARGET := clojure
run-visual-test-ios: XCODE_DERIVED_DATA := $(HOME)/Library/Developer/Xcode/DerivedData
run-visual-test-ios: APPLICATION_NAME := $(shell ls $(XCODE_DERIVED_DATA) | grep -E '\bStatusIm-')
run-visual-test-ios: APPLICATION_NAME := StatusIm-brfnruzfrkkycpbndmdoeyrigthc
run-visual-test-ios: export TEST_BINARY_PATH := $(XCODE_DERIVED_DATA)/$(APPLICATION_NAME)/Build/Products/Debug-iphonesimulator/StatusIm.app
run-visual-test-ios: ##@test Run tests once in NodeJS
yarn install
detox build --configuration ios.sim.debug && \
detox test --configuration ios.sim.debug
#--------------
component-test-watch: export TARGET := clojure
component-test: export COMPONENT_TEST := true
component-test: export BABEL_ENV := test
component-test-watch: ##@ Watch tests and re-run no changes to cljs files
yarn install
nodemon --exec 'yarn shadow-cljs compile component-test && jest --config=test/jest/jest.config.js' -e cljs
component-test: export TARGET := clojure
component-test: export COMPONENT_TEST := true
component-test: export BABEL_ENV := test
component-test: ##@test Run tests once in NodeJS
# Here we create the gyp bindings for nodejs
yarn install
yarn shadow-cljs compile component-test && \
jest --config=test/jest/jest.config.js
# Other
#--------------

24
babel.config.js Normal file
View File

@ -0,0 +1,24 @@
module.exports = {
"presets": [
"module:metro-react-native-babel-preset"
],
"plugins": [
"react-native-reanimated/plugin"
],
"env": {
"test": {
"presets": [
'@babel/preset-react',
[
'@babel/preset-env',
{
targets: {
node: '14',
},
},
],
],
}
}
}

View File

@ -74,7 +74,7 @@
"react-native-touch-id": "^4.4.1",
"react-native-webview": "git+https://github.com/status-im/react-native-webview.git#refs/tags/v11.16.0-status",
"react-syntax-highlighter": "^15.5.0",
"rn-emoji-keyboard": "git+https://github.com/status-im/rn-emoji-keyboard.git#refs/tags/v0.4.3",
"rn-emoji-keyboard": "0.7.0",
"tdigest": "^0.1.1"
},
"devDependencies": {
@ -82,15 +82,21 @@
"@babel/helper-builder-react-jsx": "7.0.0",
"@babel/plugin-transform-block-scoping": "7.0.0",
"@babel/preset-env": "7.1.0",
"@babel/preset-react": "^7.18.6",
"@babel/register": "7.0.0",
"@jest/globals": "^25.1.0",
"@mapbox/node-pre-gyp": "^1.0.9",
"@testing-library/jest-native": "^5.0.0",
"@testing-library/react-native": "^11.2.0",
"@types/jest": "^28.1.6",
"detox": "^19.9.1",
"jest": "^25.1.0",
"jest-circus": "^26.0.0",
"jest-image-snapshot": "^5.1.0",
"jest": "^28.1.3",
"nodemon": "^2.0.16",
"nyc": "^14.1.1",
"process": "0.11.10",
"react-test-renderer": "16.13.1",
"rn-snoopy": "git+https://github.com/status-im/rn-snoopy.git#refs/tags/v2.0.2-status",
"shadow-cljs": "2.11.16"
},

View File

@ -64,15 +64,15 @@
{:closure-defines
{status-im.utils.config/POKT_TOKEN #shadow/env "POKT_TOKEN"
status-im.utils.config/OPENSEA_API_KEY #shadow/env "OPENSEA_API_KEY"}
:compiler-options {:output-feature-set :es6
:compiler-options {:output-feature-set :es6
;;disable for android build as there
;;is an intermittent warning with deftype
:warnings-as-errors false
:infer-externs :auto
:static-fns true
:fn-invoke-direct true
:optimizations :advanced
:js-options {:js-provider :closure}}}}
:warnings-as-errors false
:infer-externs :auto
:static-fns true
:fn-invoke-direct true
:optimizations :advanced
:js-options {:js-provider :closure}}}}
;; the tests are ran with node, react-native dependencies are mocked
;; by using node --require override.js, which uses the node-library
;; produced by the target :mocks below and redefines node require
@ -106,4 +106,11 @@
:output-to "target/mocks/mocks.js"
:output-dir "target/mocks"
:compiler-options {:optimizations :simple
:source-map false}}}}
:source-map false}}
:component-test {:target :npm-module
:entries [quo2.core-spec]
:ns-regexp "-component-spec$"
:output-dir "component-spec"
:compiler-options {:warnings-as-errors false
:static-fns false
:infer-externs true}}}}

View File

@ -4,9 +4,14 @@
(def icon-path "./resources/images/icons2/")
(defn combine-path [path el]
(if (System/getenv "COMPONENT_TEST")
(str "." path el "@2x.png")
(str "." path el ".png")))
(defn require-icon [size path]
(fn [el]
(let [s (str "." path el ".png")
(let [s (combine-path path el)
k (-> el
(cstr/replace "_" "-")
(cstr/replace " " "-")

View File

@ -0,0 +1,14 @@
(ns quo2.components.selectors.--tests--.selectors-component-spec
(:require ["@testing-library/react-native" :as rtl]
[quo2.components.selectors.selectors :as selectors]
[reagent.core :as reagent]))
(defn render-toggle
([]
(rtl/render (reagent/as-element [selectors/toggle {:disabled? (:disabled? false)}]))))
(js/global.test "default render of toggle component"
(fn []
(render-toggle)
(-> (js/expect (rtl/screen.getByTestId "toggle-component"))
(.toBeTruthy))))

View File

@ -133,7 +133,8 @@
:border-radius 20
:background-color (get-color @checked? disabled? blurred-background?)})
:accessibility-label (str "toggle-" (if @checked? "on" "off"))
:accessibility-role :checkbox}
:accessibility-role :checkbox
:testID "toggle-component"}
[rn/view {:style
{:margin-left (if @checked? 12 2)
:height 16

2
src/quo2/core_spec.cljs Normal file
View File

@ -0,0 +1,2 @@
(ns quo2.core-spec
(:require [quo2.components.selectors.--tests--.selectors-component-spec]))

View File

@ -5,8 +5,11 @@
;;TODO (14/11/22 flexsurfer) this namespace has been moved to the status-im2 namespace, we keep this only for old (status 1.0) code,
;; can be removed with old code later
(def get-keyword
(if js/global.__TEST__ str keyword))
(def default-device-language
(keyword (.-language react-native-languages)))
(get-keyword (.-language react-native-languages)))
(def languages #{:ar :bn :de :el :en :es :es_419 :es_AR :fil :fr :hi :id :in :it :ja :ko :ms :nl :pl :pt :pt_BR :ru :tr :vi :zh :zh_Hant :zh_TW})
@ -16,17 +19,17 @@
(defn valid-language [lang]
(if (contains? languages lang)
(keyword lang)
(get-keyword lang)
(let [parts (string/split (name lang) #"[\-\_]")
short-lang (keyword (str (first parts) "_" (second parts)))
shortest-lang (keyword (first parts))]
short-lang (get-keyword (str (first parts) "_" (second parts)))
shortest-lang (get-keyword (first parts))]
(if (and (> (count parts) 2) (contains? languages short-lang))
short-lang
(when (contains? languages shortest-lang)
shortest-lang)))))
(defn require-translation [lang-key]
(when-let [lang (valid-language (keyword lang-key))]
(when-let [lang (valid-language (get-keyword lang-key))]
(case lang
:ar (js/require "../translations/ar.json")
:bn (js/require "../translations/bn.json")
@ -63,10 +66,10 @@
(assoc default-device-language
(require-translation (-> (name default-device-language)
(string/replace "-" "_")
keyword)))))
get-keyword)))))
(defn load-language [lang]
(when-let [lang-key (valid-language (keyword lang))]
(when-let [lang-key (valid-language (get-keyword lang))]
(when-not (contains? @loaded-languages lang-key)
(aset (.-translations i18n-js)
lang

22
test/jest/jest.config.js Normal file
View File

@ -0,0 +1,22 @@
module.exports = {
"preset": "react-native",
"setupFilesAfterEnv": ["@testing-library/jest-native/extend-expect"
, "../test/jest/jestSetup.js"
],
"setupFiles": [
],
"testPathIgnorePatterns": [
],
"testTimeout": 60000,
"transformIgnorePatterns": [
"/node_modules/(?!(@react-native|react-native-image-crop-picker|@react-native-community|react-native-linear-gradient|react-native-background-timer|react-native|rn-emoji-keyboard|react-native-languages|react-native-shake|react-native-reanimated)/).*/"
],
"globals": {
"__TEST__": true
},
"testEnvironment": "node",
rootDir: "../../component-spec",
testMatch: [
"**/*__tests__*"
]
}

43
test/jest/jestSetup.js Normal file
View File

@ -0,0 +1,43 @@
const WebSocket = require('ws');
const { NativeModules } = require('react-native');
require('@react-native-async-storage/async-storage/jest/async-storage-mock');
require('react-native-gesture-handler/jestSetup');
jest.mock('react-native-reanimated', () => {
const Reanimated = require('react-native-reanimated/mock');
// The mock for `call` immediately calls the callback which is incorrect
// So we override it with a no-op
Reanimated.default.call = () => { };
return Reanimated;
});
jest.mock('@react-native-async-storage/async-storage', () => mockAsyncStorage);
jest.mock('react-native-navigation', () => ({
getNavigationConstants:
() => ({ constants: [] }),
Navigation: { constants: async () => { } }
}));
jest.mock("react-native-background-timer", () => ({}))
jest.mock('react-native-languages', () => ({
RNLanguages: {
language: 'en',
languages: ['en'],
},
default: {},
}));
NativeModules.ReactLocalization = {
language: 'en',
locale: 'en'
};
global.navigator = {
userAgent: 'node',
}
global.WebSocket = WebSocket

View File

@ -1,13 +1,14 @@
{
"globalSetup": "./global-setup.js",
"globalTeardown": "./global-teardown.js",
"setupFilesAfterEnv": ["./setup.js"],
"globalSetup": "./visual-test/global-setup.js",
"globalTeardown": "./visual-test/global-teardown.js",
"setupFilesAfterEnv": ["./visual-test/setup.js"],
"maxWorkers": 1,
"testEnvironment": "./environment",
"testEnvironment": "./visual-test/environment",
"testRunner": "jest-circus/runner",
"testTimeout": 120000,
"testRegex": "\\.e2e\\.js$",
"roots": ["../src/"],
"roots": ["./src/"],
"reporters": ["detox/runners/jest/streamlineReporter"],
"verbose": true
"verbose": true,
"rootDir": "../"
}

View File

@ -2,7 +2,7 @@ const { configureToMatchImageSnapshot } = require('jest-image-snapshot');
const fs = require('fs');
const path = require('path');
const kebabCase = require('lodash/kebabCase');
const {expect} = require('expect');
const expect = require('expect');
const toMatchImage = configureToMatchImageSnapshot({
@ -15,8 +15,8 @@ expect.extend({ toMatchImage });
expect.extend({
async toMatchImageSnapshot(screenName) {
const platform = await device.getPlatform();
const deviceName = await device.name.split(' ').slice(1).join ('') ;
const deviceType = 'iPhone 11 Pro' ;
const deviceName = await device.name.split(' ').slice(1).join('');
const deviceType = 'iPhone 11 Pro';
const SNAPSHOTS_DIR = `__image_snapshots__/${platform}/${deviceType}`;
@ -37,5 +37,5 @@ global.jestExpect = expect
beforeAll(async () => {
await device.launchApp();
});
await device.launchApp();
});

3140
yarn.lock

File diff suppressed because it is too large Load Diff