diff --git a/.github/actions/prepare-ios-tests/action.yml b/.github/actions/prepare-ios-tests/action.yml deleted file mode 100644 index 6465f0db99bd2c..00000000000000 --- a/.github/actions/prepare-ios-tests/action.yml +++ /dev/null @@ -1,22 +0,0 @@ -name: prepare-ios-tests -description: Prepare iOS Tests -runs: - using: composite - steps: - - name: Run Ruby Tests - shell: bash - run: | - cd packages/react-native/scripts - sh run_ruby_tests.sh - - name: Boot iPhone Simulator - shell: bash - run: source scripts/.tests.env && xcrun simctl boot "$IOS_DEVICE" || true - - name: "Brew: Tap wix/brew" - shell: bash - run: brew tap wix/brew - - name: brew install applesimutils watchman - shell: bash - run: brew install applesimutils watchman - - name: Configure Watchman - shell: bash - run: echo "{}" > .watchmanconfig diff --git a/.github/actions/test-ios-rntester/action.yml b/.github/actions/test-ios-rntester/action.yml index 4cb56919915181..1d71f022e051b2 100644 --- a/.github/actions/test-ios-rntester/action.yml +++ b/.github/actions/test-ios-rntester/action.yml @@ -13,9 +13,6 @@ inputs: ruby-version: description: The version of ruby that must be used default: 2.6.10 - run-unit-tests: - description: whether unit tests should run or not. - default: "false" hermes-tarball-artifacts-dir: description: The directory where the hermes tarball artifacts are stored default: /tmp/hermes/hermes-runtime-darwin @@ -51,9 +48,6 @@ runs: uses: ruby/setup-ruby@v1 with: ruby-version: ${{ inputs.ruby-version }} - - name: Prepare IOS Tests - if: ${{ inputs.run-unit-tests == 'true' }} - uses: ./.github/actions/prepare-ios-tests - name: Set HERMES_ENGINE_TARBALL_PATH envvar if Hermes tarball is present shell: bash run: | @@ -147,34 +141,3 @@ runs: echo "App found at $APP_PATH" echo "app-path=$APP_PATH" >> $GITHUB_ENV - - name: "Run Tests: iOS Unit and Integration Tests" - if: ${{ inputs.run-unit-tests == 'true' }} - shell: bash - run: yarn test-ios - - - name: Zip Derived data folder - if: ${{ inputs.run-unit-tests == 'true' }} - shell: bash - run: | - echo "zipping tests results" - cd /Users/distiller/Library/Developer/Xcode - XCRESULT_PATH=$(find . -name '*.xcresult') - tar -zcvf xcresults.tar.gz $XCRESULT_PATH - - name: Upload artifact - uses: actions/upload-artifact@v4.3.4 - if: ${{ inputs.run-unit-tests == 'true' }} - with: - name: xcresults - path: /Users/distiller/Library/Developer/Xcode/xcresults.tar.gz - - name: Upload RNTester App - if: ${{ inputs.use-frameworks == 'StaticLibraries' && inputs.ruby-version == '2.6.10' }} # This is needed to avoid conflicts with the artifacts - uses: actions/upload-artifact@v4.3.4 - with: - name: RNTesterApp-${{ inputs.architecture }}-${{ inputs.jsengine }}-${{ inputs.flavor }} - path: ${{ env.app-path }} - - name: Store test results - if: ${{ inputs.run-unit-tests == 'true' }} - uses: actions/upload-artifact@v4.3.4 - with: - name: test-results - path: ./reports/junit diff --git a/.github/workflows/test-all.yml b/.github/workflows/test-all.yml index ae8cc58ce07c3a..640a87cdc05f4d 100644 --- a/.github/workflows/test-all.yml +++ b/.github/workflows/test-all.yml @@ -189,7 +189,6 @@ jobs: with: jsengine: ${{ matrix.jsengine }} architecture: ${{ matrix.architecture }} - run-unit-tests: "false" use-frameworks: StaticLibraries hermes-version: ${{ needs.prepare_hermes_workspace.outputs.hermes-version }} react-native-version: ${{ needs.prepare_hermes_workspace.outputs.react-native-version }} diff --git a/packages/react-native/scripts/run_ruby_tests.sh b/packages/react-native/scripts/run_ruby_tests.sh deleted file mode 100755 index 21a97f7fedab20..00000000000000 --- a/packages/react-native/scripts/run_ruby_tests.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/bash -# 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. - -set -f - -basepath=$(dirname "${0}") - -# shellcheck disable=SC2207 -files=( $(find . -name '*-test.rb') ) - -test_suite="${basepath}/all_tests.rb" -touch "${test_suite}" - -echo "require \"test/unit\"" > "${test_suite}" -echo "discovered the following files:" -for i in "${files[@]}" -do - filename="${i#"${basepath}/"}" - echo "${filename}" - echo "require_relative \"${filename}\"" >> "${test_suite}" -done - -ruby -Itest "${test_suite}" -RES=$? -rm "${test_suite}" -exit $RES diff --git a/packages/rn-tester/IntegrationTests/AccessibilityManagerTest.js b/packages/rn-tester/IntegrationTests/AccessibilityManagerTest.js deleted file mode 100644 index ee14843aa96729..00000000000000 --- a/packages/rn-tester/IntegrationTests/AccessibilityManagerTest.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * 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. - * - * @format - * @flow strict-local - */ - -import invariant from 'invariant'; -import * as React from 'react'; -import {useEffect} from 'react'; -import {DeviceEventEmitter, NativeModules, View} from 'react-native'; -import NativeAccessibilityManager from 'react-native/Libraries/Components/AccessibilityInfo/NativeAccessibilityManager'; - -const {TestModule} = NativeModules; - -function AccessibilityManagerTest(): React.Node { - useEffect(() => { - invariant( - NativeAccessibilityManager, - "NativeAccessibilityManager doesn't exist", - ); - - NativeAccessibilityManager.setAccessibilityContentSizeMultipliers({ - extraSmall: 1.0, - small: 2.0, - medium: 3.0, - large: 4.0, - extraLarge: 5.0, - extraExtraLarge: 6.0, - extraExtraExtraLarge: 7.0, - accessibilityMedium: 8.0, - accessibilityLarge: 9.0, - accessibilityExtraLarge: 10.0, - accessibilityExtraExtraLarge: 11.0, - accessibilityExtraExtraExtraLarge: 12.0, - }); - - const subscription = DeviceEventEmitter.addListener( - 'didUpdateDimensions', - update => { - TestModule.markTestPassed(update.window.fontScale === 4.0); - }, - ); - - return () => { - subscription.remove(); - }; - }, []); - - return ; -} - -export default AccessibilityManagerTest; diff --git a/packages/rn-tester/IntegrationTests/AppEventsTest.js b/packages/rn-tester/IntegrationTests/AppEventsTest.js deleted file mode 100644 index 93997247584121..00000000000000 --- a/packages/rn-tester/IntegrationTests/AppEventsTest.js +++ /dev/null @@ -1,86 +0,0 @@ -/** - * 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. - * - * @format - * @flow - */ - -'use strict'; - -import * as React from 'react'; -import {useEffect, useState} from 'react'; -import { - NativeAppEventEmitter, - NativeModules, - StyleSheet, - Text, - View, -} from 'react-native'; -import deepDiffer from 'react-native/Libraries/Utilities/differ/deepDiffer'; - -const {TestModule} = NativeModules; - -const TEST_PAYLOAD = {foo: 'bar'}; - -type AppEvent = { - data: Object, - ts: number, -}; - -type State = { - sent: 'none' | AppEvent, - received: 'none' | AppEvent, - elapsed?: string, -}; - -function AppEventsTest(): React.Node { - const [state, setState] = useState({ - sent: 'none', - received: 'none', - }); - - useEffect(() => { - const receiveEvent = (event: any) => { - if (deepDiffer(event.data, TEST_PAYLOAD)) { - throw new Error('Received wrong event: ' + JSON.stringify(event)); - } - const elapsed = Date.now() - event.ts + 'ms'; - setState(prevState => ({ - ...prevState, - received: event, - elapsed, - })); - TestModule.markTestCompleted(); - }; - - const listener = NativeAppEventEmitter.addListener( - 'testEvent', - receiveEvent, - ); - - const event = {data: TEST_PAYLOAD, ts: Date.now()}; - TestModule.sendAppEvent('testEvent', event); - setState(prevState => ({...prevState, sent: event})); - - return () => { - listener.remove(); - }; - }, []); - - return ( - - {JSON.stringify(state, null, ' ')} - - ); -} - -const styles = StyleSheet.create({ - container: { - margin: 40, - }, -}); - -export default AppEventsTest; diff --git a/packages/rn-tester/IntegrationTests/GlobalEvalWithSourceUrlTest.js b/packages/rn-tester/IntegrationTests/GlobalEvalWithSourceUrlTest.js deleted file mode 100644 index 3dd3a43ca1288c..00000000000000 --- a/packages/rn-tester/IntegrationTests/GlobalEvalWithSourceUrlTest.js +++ /dev/null @@ -1,83 +0,0 @@ -/** - * 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. - * - * @format - * @flow strict-local - */ - -'use strict'; - -import type {ExtendedError} from 'react-native/Libraries/Core/ExtendedError'; - -import * as React from 'react'; -import {useEffect} from 'react'; -import {NativeModules, View} from 'react-native'; -import parseErrorStack from 'react-native/Libraries/Core/Devtools/parseErrorStack'; - -const {TestModule} = NativeModules; - -function GlobalEvalWithSourceUrlTest(): React.Node { - useEffect(() => { - if (typeof global.globalEvalWithSourceUrl !== 'function') { - throw new Error( - 'Expected to find globalEvalWithSourceUrl function on global object but found ' + - typeof global.globalEvalWithSourceUrl, - ); - } - const value = global.globalEvalWithSourceUrl('42'); - if (value !== 42) { - throw new Error( - 'Expected globalEvalWithSourceUrl(expression) to return a value', - ); - } - let syntaxError: ?ExtendedError; - try { - global.globalEvalWithSourceUrl('{'); - } catch (e) { - syntaxError = e; - } - if (!syntaxError) { - throw new Error( - 'Expected globalEvalWithSourceUrl to throw on a syntax error', - ); - } - // Hermes throws an Error instead of a SyntaxError - // https://github.com/facebook/hermes/issues/400 - if ( - syntaxError.jsEngine !== 'hermes' && - !(syntaxError instanceof SyntaxError) - ) { - throw new Error( - 'Expected globalEvalWithSourceUrl to throw SyntaxError on a syntax error', - ); - } - const url = 'http://example.com/foo.js'; - let error; - try { - global.globalEvalWithSourceUrl('throw new Error()', url); - } catch (e) { - error = e; - } - if (!error) { - throw new Error( - 'Expected globalEvalWithSourceUrl to throw an Error object', - ); - } - const parsedStack = parseErrorStack(error?.stack); - if (parsedStack[0].file !== url) { - throw new Error( - `Expected first eval stack frame to be in ${url} but found ${String( - parsedStack[0].file, - )}`, - ); - } - TestModule.markTestCompleted(); - }, []); - - return ; -} - -export default GlobalEvalWithSourceUrlTest; diff --git a/packages/rn-tester/IntegrationTests/ImageCachePolicyTest.js b/packages/rn-tester/IntegrationTests/ImageCachePolicyTest.js deleted file mode 100644 index d188e55b2b6ef9..00000000000000 --- a/packages/rn-tester/IntegrationTests/ImageCachePolicyTest.js +++ /dev/null @@ -1,108 +0,0 @@ -/** - * 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. - * - * @format - * @flow strict-local - */ - -'use strict'; - -import type {ImageURISource} from 'react-native'; - -import * as React from 'react'; -import {useEffect, useState} from 'react'; -import {Image, NativeModules, StyleSheet, Text, View} from 'react-native'; - -const {TestModule} = NativeModules; - -/* - * The reload and force-cache tests don't actually verify that the complete functionality. - * - * reload: Should have the server set a long cache header, then swap the image on next load - * with the test comparing the old image to the new image and making sure they are different. - * - * force-cache: Should do the above but set a no-cache header. The test should compare the first - * image with the new one and make sure they are the same. - */ - -const TESTS = ['only-if-cached', 'default', 'reload', 'force-cache']; - -function ImageCachePolicyTest(): React.Node { - const [state, setState] = useState({ - 'only-if-cached': undefined, - default: undefined, - reload: undefined, - 'force-cache': undefined, - }); - - const testComplete = ( - name: $NonMaybeType, - pass: boolean, - ) => { - setState(prevState => ({ - ...prevState, - [name]: pass, - })); - }; - - useEffect(() => { - const results = TESTS.map(key => state[key]); - - if (!results.includes(undefined)) { - const result = results.reduce((x, y) => (x === y) === true, true); - TestModule.markTestPassed(result); - } - }, [state]); - - return ( - - Hello - testComplete('only-if-cached', false)} - onError={() => testComplete('only-if-cached', true)} - style={styles.base} - /> - testComplete('default', true)} - onError={() => testComplete('default', false)} - style={styles.base} - /> - testComplete('reload', true)} - onError={() => testComplete('reload', false)} - style={styles.base} - /> - testComplete('force-cache', true)} - onError={() => testComplete('force-cache', false)} - style={styles.base} - /> - - ); -} - -const getImageSource = (cache: ImageURISource['cache']) => ({ - uri: - 'https://raw.githubusercontent.com/facebook/react-native/HEAD/Libraries/NewAppScreen/components/logo.png?cacheBust=notinCache' + - Date.now(), - cache, -}); - -const styles = StyleSheet.create({ - container: { - flex: 1, - }, - base: { - width: 100, - height: 100, - }, -}); - -export default ImageCachePolicyTest; diff --git a/packages/rn-tester/IntegrationTests/ImageSnapshotTest.js b/packages/rn-tester/IntegrationTests/ImageSnapshotTest.js deleted file mode 100644 index fd6ff9f7fe4a6e..00000000000000 --- a/packages/rn-tester/IntegrationTests/ImageSnapshotTest.js +++ /dev/null @@ -1,39 +0,0 @@ -/** - * 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. - * - * @format - * @flow strict-local - */ - -'use strict'; - -import * as React from 'react'; -import {useEffect} from 'react'; -import {Image, NativeModules} from 'react-native'; - -const {TestModule} = NativeModules; - -function ImageSnapshotTest(): React.Node { - useEffect(() => { - if (!TestModule.verifySnapshot) { - throw new Error('TestModule.verifySnapshot not defined.'); - } - }, []); - - const done = (success: boolean) => { - TestModule.markTestPassed(success); - }; - - return ( - TestModule.verifySnapshot(done)} - /> - ); -} - -export default ImageSnapshotTest; diff --git a/packages/rn-tester/IntegrationTests/IntegrationTestHarnessTest.js b/packages/rn-tester/IntegrationTests/IntegrationTestHarnessTest.js deleted file mode 100644 index 3790c8f52f3072..00000000000000 --- a/packages/rn-tester/IntegrationTests/IntegrationTestHarnessTest.js +++ /dev/null @@ -1,65 +0,0 @@ -/** - * 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. - * - * @format - * @flow - */ - -'use strict'; - -import * as React from 'react'; -import {useEffect, useState} from 'react'; -import {NativeModules, StyleSheet, Text, View} from 'react-native'; - -const {TestModule} = NativeModules; - -type Props = $ReadOnly<{ - shouldThrow?: boolean, - waitOneFrame?: boolean, -}>; - -function IntegrationTestHarnessTest(props: Props): React.Node { - const [done, setDone] = useState(false); - - useEffect(() => { - const runTest = () => { - if (props.shouldThrow) { - throw new Error('Throwing error because shouldThrow'); - } - if (!TestModule) { - throw new Error('RCTTestModule is not registered.'); - } else if (!TestModule.markTestCompleted) { - throw new Error('RCTTestModule.markTestCompleted not defined.'); - } - setDone(true); - TestModule.markTestCompleted(); - }; - - if (props.waitOneFrame) { - requestAnimationFrame(runTest); - } else { - runTest(); - } - }, [props.shouldThrow, props.waitOneFrame]); - - return ( - - - {IntegrationTestHarnessTest.name + ': '} - {done ? 'Done' : 'Testing...'} - - - ); -} - -const styles = StyleSheet.create({ - container: { - backgroundColor: 'white', - padding: 40, - }, -}); - -export default IntegrationTestHarnessTest; diff --git a/packages/rn-tester/IntegrationTests/IntegrationTestsApp.js b/packages/rn-tester/IntegrationTests/IntegrationTestsApp.js deleted file mode 100644 index 4da2f6a35da3a7..00000000000000 --- a/packages/rn-tester/IntegrationTests/IntegrationTestsApp.js +++ /dev/null @@ -1,114 +0,0 @@ -/** - * 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. - * - * @format - * @flow - */ - -'use strict'; - -require('react-native/Libraries/Core/InitializeCore'); -const React = require('react'); -const ReactNative = require('react-native'); -const {AppRegistry, ScrollView, StyleSheet, Text, TouchableOpacity, View} = - ReactNative; - -// Keep this list in sync with RNTesterIntegrationTests.m -const TESTS = [ - require('./IntegrationTestHarnessTest'), - require('./TimersTest'), - require('./LayoutEventsTest'), - require('./AppEventsTest'), - require('./SimpleSnapshotTest'), - require('./ImageCachePolicyTest'), - require('./ImageSnapshotTest'), - require('./PromiseTest'), - require('./SyncMethodTest'), - require('./WebSocketTest'), - require('./AccessibilityManagerTest'), - require('./GlobalEvalWithSourceUrlTest'), -]; - -TESTS.forEach(test => - AppRegistry.registerComponent( - test.displayName || test.name || '', - /* $FlowFixMe[incompatible-call] (>=0.54.0 site=react_native_fb,react_native_ - * oss) This comment suppresses an error found when Flow v0.54 was deployed. - * To see the error delete this comment and run Flow. */ - () => test, - ), -); - -// Modules required for integration tests -require('./LoggingTestModule'); - -type Test = any; - -class IntegrationTestsApp extends React.Component<{...}, $FlowFixMeState> { - state: {test: ?Test} = { - test: (null: ?Test), - }; - - render(): React.Node { - if (this.state.test) { - return ( - - {/* $FlowFixMe[type-as-value] (>=0.53.0 site=react_native_fb,react_ - * native_oss) This comment suppresses an error when upgrading - * Flow's support for React. To see the error delete this comment - * and run Flow. */} - - - ); - } - return ( - - - Click on a test to run it in this shell for easier debugging and - development. Run all tests in the testing environment with cmd+U in - Xcode. - - - - {TESTS.map(test => [ - this.setState({test})} - /* $FlowFixMe[incompatible-type] (>=0.115.0 site=react_native_fb) - * This comment suppresses an error found when Flow v0.115 was - * deployed. To see the error, delete this comment and run Flow. - */ - style={styles.row}> - - {test.displayName || test.name} - - , - , - ])} - - - ); - } -} - -const styles = StyleSheet.create({ - container: { - backgroundColor: 'white', - marginTop: 40, - margin: 15, - }, - row: { - padding: 10, - }, - testName: { - fontWeight: '500', - }, - separator: { - height: 1, - backgroundColor: '#bbbbbb', - }, -}); - -AppRegistry.registerComponent('IntegrationTestsApp', () => IntegrationTestsApp); diff --git a/packages/rn-tester/IntegrationTests/LayoutEventsTest.js b/packages/rn-tester/IntegrationTests/LayoutEventsTest.js deleted file mode 100644 index 141a20d29709d6..00000000000000 --- a/packages/rn-tester/IntegrationTests/LayoutEventsTest.js +++ /dev/null @@ -1,204 +0,0 @@ -/** - * 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. - * - * @format - * @flow strict-local - */ - -'use strict'; - -import type {LayoutChangeEvent, LayoutRectangle} from 'react-native'; -import type {ViewStyleProp} from 'react-native/Libraries/StyleSheet/StyleSheet'; - -const React = require('react'); -const ReactNative = require('react-native'); -const deepDiffer = - require('react-native/Libraries/Utilities/differ/deepDiffer').default; - -const {Image, LayoutAnimation, StyleSheet, Text, View} = ReactNative; -const {TestModule} = ReactNative.NativeModules; -function debug(...args: Array) { - // console.log.apply(null, arguments); -} - -type Props = $ReadOnly<{}>; - -type State = { - didAnimation: boolean, - extraText?: string, - imageLayout?: LayoutRectangle, - textLayout?: LayoutRectangle, - viewLayout?: LayoutRectangle, - viewStyle?: ViewStyleProp, - containerStyle?: ViewStyleProp, - ... -}; - -class LayoutEventsTest extends React.Component { - _view: ?React.ElementRef; - _img: ?React.ElementRef; - _txt: ?React.ElementRef; - - state: State = { - didAnimation: false, - }; - - animateViewLayout() { - debug('animateViewLayout invoked'); - LayoutAnimation.configureNext(LayoutAnimation.Presets.spring, () => { - debug('animateViewLayout done'); - this.checkLayout(this.addWrapText); - }); - this.setState({viewStyle: {margin: 60}}); - } - - addWrapText: () => void = () => { - debug('addWrapText invoked'); - this.setState( - {extraText: ' And a bunch more text to wrap around a few lines.'}, - () => this.checkLayout(this.changeContainer), - ); - }; - - changeContainer: () => void = () => { - debug('changeContainer invoked'); - this.setState({containerStyle: {width: 280}}, () => - this.checkLayout(TestModule.markTestCompleted), - ); - }; - - checkLayout: (next?: ?() => void) => void = (next?: ?() => void) => { - const view = this._view; - const txt = this._txt; - const img = this._img; - - if (view == null || txt == null || img == null) { - return; - } - - view.measure((x, y, width, height) => { - this.compare( - 'view', - {x, y, width, height}, - this.state.viewLayout || null, - ); - if (typeof next === 'function') { - next(); - } else if (!this.state.didAnimation) { - // Trigger first state change after onLayout fires - this.animateViewLayout(); - this.state.didAnimation = true; - } - }); - - txt.measure((x, y, width, height) => { - this.compare('txt', {x, y, width, height}, this.state.textLayout); - }); - - img.measure((x, y, width, height) => { - this.compare('img', {x, y, width, height}, this.state.imageLayout); - }); - }; - - compare( - node: string, - measured: LayoutRectangle, - onLayout?: ?LayoutRectangle, - ): void { - if (deepDiffer(measured, onLayout)) { - const data = {measured, onLayout}; - throw new Error( - node + - ' onLayout mismatch with measure ' + - JSON.stringify(data, null, ' '), - ); - } - } - - onViewLayout: (e: LayoutChangeEvent) => void = (e: LayoutChangeEvent) => { - // $FlowFixMe[incompatible-call] - debug('received view layout event\n', e.nativeEvent); - this.setState({viewLayout: e.nativeEvent.layout}, this.checkLayout); - }; - - onTextLayout: (e: LayoutChangeEvent) => void = (e: LayoutChangeEvent) => { - // $FlowFixMe[incompatible-call] - debug('received text layout event\n', e.nativeEvent); - this.setState({textLayout: e.nativeEvent.layout}, this.checkLayout); - }; - - onImageLayout: (e: LayoutChangeEvent) => void = (e: LayoutChangeEvent) => { - // $FlowFixMe[incompatible-call] - debug('received image layout event\n', e.nativeEvent); - this.setState({imageLayout: e.nativeEvent.layout}, this.checkLayout); - }; - - render(): React.Node { - const viewStyle = [styles.view, this.state.viewStyle]; - const textLayout = this.state.textLayout || {width: '?', height: '?'}; - const imageLayout = this.state.imageLayout || {x: '?', y: '?'}; - debug('viewLayout', this.state.viewLayout); - return ( - - { - this._view = ref; - }} - onLayout={this.onViewLayout} - style={viewStyle}> - { - this._img = ref; - }} - onLayout={this.onImageLayout} - style={styles.image} - source={{uri: 'uie_thumb_big.png'}} - /> - { - this._txt = ref; - }} - onLayout={this.onTextLayout} - style={styles.text}> - A simple piece of text.{this.state.extraText} - - - {'\n'} - Text w/h: {textLayout.width}/{textLayout.height + '\n'} - Image x/y: {imageLayout.x}/{imageLayout.y} - - - - ); - } -} - -const styles = StyleSheet.create({ - container: { - margin: 40, - }, - view: { - margin: 20, - padding: 12, - borderColor: 'black', - borderWidth: 0.5, - backgroundColor: 'transparent', - }, - text: { - alignSelf: 'flex-start', - borderColor: 'rgba(0, 0, 255, 0.2)', - borderWidth: 0.5, - }, - image: { - width: 50, - height: 50, - marginBottom: 10, - alignSelf: 'center', - }, -}); - -LayoutEventsTest.displayName = 'LayoutEventsTest'; -module.exports = LayoutEventsTest; diff --git a/packages/rn-tester/IntegrationTests/LoggingTestModule.js b/packages/rn-tester/IntegrationTests/LoggingTestModule.js deleted file mode 100644 index 44132cf229dc5a..00000000000000 --- a/packages/rn-tester/IntegrationTests/LoggingTestModule.js +++ /dev/null @@ -1,41 +0,0 @@ -/** - * 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. - * - * @format - */ - -'use strict'; - -const invariant = require('invariant'); -const BatchedBridge = - require('react-native/Libraries/BatchedBridge/BatchedBridge').default; - -const LoggingTestModule = { - logToConsole: function (str) { - console.log(str); - }, - logToConsoleAfterWait: function (str, timeout_ms) { - setTimeout(function () { - console.log(str); - }, timeout_ms); - }, - warning: function (str) { - console.warn(str); - }, - invariant: function (str) { - invariant(false, str); - }, - logErrorToConsole: function (str) { - console.error(str); - }, - throwError: function (str) { - throw new Error(str); - }, -}; - -BatchedBridge.registerCallableModule('LoggingTestModule', LoggingTestModule); - -module.exports = LoggingTestModule; diff --git a/packages/rn-tester/IntegrationTests/PromiseTest.js b/packages/rn-tester/IntegrationTests/PromiseTest.js deleted file mode 100644 index e9464d735b051a..00000000000000 --- a/packages/rn-tester/IntegrationTests/PromiseTest.js +++ /dev/null @@ -1,86 +0,0 @@ -/** - * 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. - * - * @format - * @flow - */ - -'use strict'; - -import * as React from 'react'; -import {useEffect, useRef} from 'react'; -import {NativeModules, View} from 'react-native'; - -const {TestModule} = NativeModules; - -function PromiseTest(): React.Node { - const shouldResolve = useRef(false); - const shouldReject = useRef(false); - const shouldSucceedAsync = useRef(false); - const shouldThrowAsync = useRef(false); - - const testShouldResolve = () => { - return TestModule.shouldResolve() - .then(() => { - shouldResolve.current = true; - }) - .catch(() => { - shouldResolve.current = false; - }); - }; - - const testShouldReject = () => { - return TestModule.shouldReject() - .then(() => { - shouldReject.current = false; - }) - .catch(() => { - shouldReject.current = true; - }); - }; - - const testShouldSucceedAsync = async () => { - try { - await TestModule.shouldResolve(); - shouldSucceedAsync.current = true; - } catch (e) { - shouldSucceedAsync.current = false; - } - }; - - const testShouldThrowAsync = async () => { - try { - await TestModule.shouldReject(); - shouldThrowAsync.current = false; - } catch (e) { - shouldThrowAsync.current = true; - } - }; - - useEffect(() => { - async function runTests() { - await Promise.all([ - testShouldResolve(), - testShouldReject(), - testShouldSucceedAsync(), - testShouldThrowAsync(), - ]); - - TestModule.markTestPassed( - shouldResolve.current && - shouldReject.current && - shouldSucceedAsync.current && - shouldThrowAsync.current, - ); - } - - runTests().catch(console.error); - }, []); - - return ; -} - -export default PromiseTest; diff --git a/packages/rn-tester/IntegrationTests/SimpleSnapshotTest.js b/packages/rn-tester/IntegrationTests/SimpleSnapshotTest.js deleted file mode 100644 index b26b540d59016e..00000000000000 --- a/packages/rn-tester/IntegrationTests/SimpleSnapshotTest.js +++ /dev/null @@ -1,57 +0,0 @@ -/** - * 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. - * - * @format - * @flow strict-local - */ - -'use strict'; - -import * as React from 'react'; -import {useEffect} from 'react'; -import {NativeModules, StyleSheet, View} from 'react-native'; - -const {TestModule} = NativeModules; - -function SimpleSnapshotTest(): React.Node { - const done = (success: boolean) => { - TestModule.markTestPassed(success); - }; - useEffect(() => { - if (!TestModule.verifySnapshot) { - throw new Error('TestModule.verifySnapshot not defined.'); - } - requestAnimationFrame(() => TestModule.verifySnapshot(done)); - }, []); - - return ( - - - - - ); -} - -const styles = StyleSheet.create({ - container: { - backgroundColor: 'white', - padding: 100, - }, - box1: { - width: 80, - height: 50, - backgroundColor: 'red', - }, - box2: { - top: -10, - left: 20, - width: 70, - height: 90, - backgroundColor: 'blue', - }, -}); - -export default SimpleSnapshotTest; diff --git a/packages/rn-tester/IntegrationTests/SyncMethodTest.js b/packages/rn-tester/IntegrationTests/SyncMethodTest.js deleted file mode 100644 index 1ee64ebe58cac4..00000000000000 --- a/packages/rn-tester/IntegrationTests/SyncMethodTest.js +++ /dev/null @@ -1,49 +0,0 @@ -/** - * 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. - * - * @format - * @flow strict-local - */ - -'use strict'; - -import * as React from 'react'; -import {useEffect} from 'react'; -import {NativeModules, View} from 'react-native'; - -const {TestModule, RNTesterTestModule} = NativeModules; - -function SyncMethodTest(): React.Node { - useEffect(() => { - if ( - RNTesterTestModule.echoString('test string value') !== 'test string value' - ) { - throw new Error('Something wrong with echoString sync method'); - } - if (RNTesterTestModule.methodThatReturnsNil() != null) { - throw new Error('Something wrong with methodThatReturnsNil sync method'); - } - let response; - RNTesterTestModule.methodThatCallsCallbackWithString('test', echo => { - response = echo; - }); - requestAnimationFrame(() => { - if (response === 'test') { - TestModule.markTestCompleted(); - } else { - throw new Error( - 'Something wrong with methodThatCallsCallbackWithString sync method, ' + - 'got response ' + - JSON.stringify(response), - ); - } - }); - }, []); - - return ; -} - -export default SyncMethodTest; diff --git a/packages/rn-tester/IntegrationTests/TimersTest.js b/packages/rn-tester/IntegrationTests/TimersTest.js deleted file mode 100644 index 45f1088dc384f6..00000000000000 --- a/packages/rn-tester/IntegrationTests/TimersTest.js +++ /dev/null @@ -1,285 +0,0 @@ -/** - * 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. - * - * @format - * @flow - */ - -'use strict'; - -const React = require('react'); -const ReactNative = require('react-native'); -const {StyleSheet, Text, View} = ReactNative; -const {TestModule} = ReactNative.NativeModules; - -type Props = $ReadOnly<{}>; - -type State = { - count: number, - done: boolean, -}; - -type ImmediateID = Object; - -class TimersTest extends React.Component { - _nextTest = () => {}; - _interval: ?IntervalID = null; - - _timeoutIDs: Set = new Set(); - _intervalIDs: Set = new Set(); - _immediateIDs: Set = new Set(); - _animationFrameIDs: Set = new Set(); - - state: State = { - count: 0, - done: false, - }; - - setTimeout(fn: () => void, time: number): TimeoutID { - const id: TimeoutID = setTimeout(() => { - this._timeoutIDs.delete(id); - fn(); - }, time); - - this._timeoutIDs.add(id); - - return id; - } - - clearTimeout(id: TimeoutID) { - this._timeoutIDs.delete(id); - clearTimeout(id); - } - - setInterval(fn: () => void, time: number): IntervalID { - const id = setInterval(() => { - fn(); - }, time); - - this._intervalIDs.add(id); - - return id; - } - - clearInterval(id: IntervalID) { - this._intervalIDs.delete(id); - clearInterval(id); - } - - setImmediate(fn: () => void): ImmediateID { - const id: any = setImmediate(() => { - this._immediateIDs.delete(id); - fn(); - }); - - this._immediateIDs.add(id); - - return id; - } - - requestAnimationFrame(fn: () => void): AnimationFrameID { - const id: AnimationFrameID = requestAnimationFrame(() => { - this._animationFrameIDs.delete(id); - fn(); - }); - - this._animationFrameIDs.add(id); - - return id; - } - - cancelAnimationFrame(id: AnimationFrameID): void { - this._animationFrameIDs.delete(id); - cancelAnimationFrame(id); - } - - componentDidMount() { - // $FlowFixMe[method-unbinding] added when improving typing for this parameters - this.setTimeout(this.testSetTimeout0, 1000); - } - - testSetTimeout0() { - // $FlowFixMe[method-unbinding] added when improving typing for this parameters - this.setTimeout(this.testSetTimeout1, 0); - } - - testSetTimeout1() { - // $FlowFixMe[method-unbinding] added when improving typing for this parameters - this.setTimeout(this.testSetTimeout50, 1); - } - - testSetTimeout50() { - // $FlowFixMe[method-unbinding] added when improving typing for this parameters - this.setTimeout(this.testRequestAnimationFrame, 50); - } - - testRequestAnimationFrame() { - // $FlowFixMe[method-unbinding] added when improving typing for this parameters - this.requestAnimationFrame(this.testSetInterval0); - } - - testSetInterval0() { - // $FlowFixMe[method-unbinding] added when improving typing for this parameters - this._nextTest = this.testSetInterval20; - // $FlowFixMe[method-unbinding] added when improving typing for this parameters - this._interval = this.setInterval(this._incrementInterval, 0); - } - - testSetInterval20() { - // $FlowFixMe[method-unbinding] added when improving typing for this parameters - this._nextTest = this.testSetImmediate; - // $FlowFixMe[method-unbinding] added when improving typing for this parameters - this._interval = this.setInterval(this._incrementInterval, 20); - } - - testSetImmediate() { - // $FlowFixMe[method-unbinding] added when improving typing for this parameters - this.setImmediate(this.testClearTimeout0); - } - - testClearTimeout0() { - const timeout = this.setTimeout(() => this._fail('testClearTimeout0'), 0); - this.clearTimeout(timeout); - this.testClearTimeout30(); - } - - testClearTimeout30() { - const timeout = this.setTimeout(() => this._fail('testClearTimeout30'), 30); - this.clearTimeout(timeout); - // $FlowFixMe[method-unbinding] added when improving typing for this parameters - this.setTimeout(this.testClearMulti, 50); - } - - testClearMulti() { - const fails = []; - fails.push(this.setTimeout(() => this._fail('testClearMulti-1'), 20)); - fails.push(this.setTimeout(() => this._fail('testClearMulti-2'), 50)); - const delayClear = this.setTimeout( - () => this._fail('testClearMulti-3'), - 50, - ); - fails.push(this.setTimeout(() => this._fail('testClearMulti-4'), 0)); - fails.push(this.setTimeout(() => this._fail('testClearMulti-5'), 10)); - - fails.forEach(timeout => this.clearTimeout(timeout)); - this.setTimeout(() => this.clearTimeout(delayClear), 20); - - // $FlowFixMe[method-unbinding] added when improving typing for this parameters - this.setTimeout(this.testOrdering, 50); - } - - testOrdering() { - // Clear timers are set first because it's more likely to uncover bugs. - let fail0; - this.setImmediate(() => this.clearTimeout(fail0)); - fail0 = this.setTimeout( - () => - this._fail( - 'testOrdering-t0, setImmediate should happen before ' + - 'setTimeout 0', - ), - 0, - ); - let failAnim; // This should fail without the t=0 fastpath feature. - this.setTimeout(() => this.cancelAnimationFrame(failAnim), 0); - failAnim = this.requestAnimationFrame(() => - this._fail( - 'testOrdering-Anim, setTimeout 0 should happen before ' + - 'requestAnimationFrame', - ), - ); - let fail25; - this.setTimeout(() => { - this.clearTimeout(fail25); - }, 20); - fail25 = this.setTimeout( - () => - this._fail( - 'testOrdering-t25, setTimeout 20 should happen before ' + - 'setTimeout 25', - ), - 25, - ); - // $FlowFixMe[method-unbinding] added when improving typing for this parameters - this.setTimeout(this.done, 50); - } - - done() { - this.setState({done: true}, () => { - TestModule.markTestCompleted(); - }); - } - - componentWillUnmount() { - for (const timeoutID of this._timeoutIDs) { - clearTimeout(timeoutID); - } - - for (const intervalID of this._intervalIDs) { - clearInterval(intervalID); - } - - for (const requestAnimationFrameID of this._animationFrameIDs) { - cancelAnimationFrame(requestAnimationFrameID); - } - - for (const immediateID of this._immediateIDs) { - clearImmediate(immediateID); - } - - this._timeoutIDs = new Set(); - this._intervalIDs = new Set(); - this._animationFrameIDs = new Set(); - this._immediateIDs = new Set(); - - if (this._interval != null) { - clearInterval(this._interval); - this._interval = null; - } - } - - render(): React.Node { - return ( - - - {this.constructor.name + ': \n'} - Intervals: {this.state.count + '\n'} - {this.state.done ? 'Done' : 'Testing...'} - - - ); - } - - _incrementInterval(): void { - if (this.state.count > 3) { - throw new Error('interval incremented past end.'); - } - if (this.state.count === 3) { - if (this._interval != null) { - this.clearInterval(this._interval); - this._interval = null; - } - // $FlowFixMe[method-unbinding] - this.setState({count: 0}, this._nextTest); - return; - } - this.setState({count: this.state.count + 1}); - } - - _fail(caller: string): void { - throw new Error('_fail called by ' + caller); - } -} - -const styles = StyleSheet.create({ - container: { - backgroundColor: 'white', - padding: 40, - }, -}); - -TimersTest.displayName = 'TimersTest'; -module.exports = TimersTest; diff --git a/packages/rn-tester/IntegrationTests/WebSocketTest.js b/packages/rn-tester/IntegrationTests/WebSocketTest.js deleted file mode 100644 index 648478bacf1011..00000000000000 --- a/packages/rn-tester/IntegrationTests/WebSocketTest.js +++ /dev/null @@ -1,153 +0,0 @@ -/** - * 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. - * - * @format - * @flow - */ - -'use strict'; - -const React = require('react'); -const ReactNative = require('react-native'); -const {View} = ReactNative; -const {TestModule} = ReactNative.NativeModules; - -const DEFAULT_WS_URL = 'ws://localhost:5555/'; - -const WS_EVENTS = ['close', 'error', 'message', 'open']; - -type State = { - url: string, - fetchStatus: ?string, - socket: ?WebSocket, - socketState: ?number, - lastSocketEvent: ?string, - lastMessage: ?string | ?ArrayBuffer, - testMessage: string, - testExpectedResponse: string, - ... -}; - -class WebSocketTest extends React.Component<{...}, State> { - state: State = { - url: DEFAULT_WS_URL, - fetchStatus: null, - socket: null, - socketState: null, - lastSocketEvent: null, - lastMessage: null, - testMessage: 'testMessage', - testExpectedResponse: 'testMessage_response', - }; - - _waitFor = (condition: any, timeout: any, callback: any) => { - let remaining = timeout; - const timeoutFunction = function () { - if (condition()) { - callback(true); - return; - } - remaining--; - if (remaining === 0) { - callback(false); - } else { - setTimeout(timeoutFunction, 1000); - } - }; - setTimeout(timeoutFunction, 1000); - }; - - _connect = () => { - const socket = new WebSocket(this.state.url); - WS_EVENTS.forEach(ev => socket.addEventListener(ev, this._onSocketEvent)); - this.setState({ - socket, - socketState: socket.readyState, - }); - }; - - _socketIsConnected = (): boolean => { - return this.state.socketState === 1; //'OPEN' - }; - - _socketIsDisconnected = (): boolean => { - return this.state.socketState === 3; //'CLOSED' - }; - - _disconnect = () => { - if (!this.state.socket) { - return; - } - this.state.socket.close(); - }; - - _onSocketEvent = (event: any) => { - const state: any = { - socketState: event.target.readyState, - lastSocketEvent: event.type, - }; - if (event.type === 'message') { - state.lastMessage = event.data; - } - this.setState(state); - }; - - _sendText = (text: string) => { - if (!this.state.socket) { - return; - } - this.state.socket.send(text); - }; - - _sendTestMessage = () => { - this._sendText(this.state.testMessage); - }; - - _receivedTestExpectedResponse = (): boolean => { - return this.state.lastMessage === this.state.testExpectedResponse; - }; - - componentDidMount() { - this.testConnect(); - } - - testConnect: () => void = () => { - this._connect(); - this._waitFor(this._socketIsConnected, 5, connectSucceeded => { - if (!connectSucceeded) { - TestModule.markTestPassed(false); - return; - } - this.testSendAndReceive(); - }); - }; - - testSendAndReceive: () => void = () => { - this._sendTestMessage(); - this._waitFor(this._receivedTestExpectedResponse, 5, messageReceived => { - if (!messageReceived) { - TestModule.markTestPassed(false); - return; - } - this.testDisconnect(); - }); - }; - - testDisconnect: () => void = () => { - this._disconnect(); - this._waitFor(this._socketIsDisconnected, 5, disconnectSucceeded => { - TestModule.markTestPassed(disconnectSucceeded); - }); - }; - - render(): React.Node { - return ; - } -} - -WebSocketTest.displayName = 'WebSocketTest'; - -module.exports = WebSocketTest; diff --git a/packages/rn-tester/IntegrationTests/blue_square.png b/packages/rn-tester/IntegrationTests/blue_square.png deleted file mode 100644 index 4974e084c63652..00000000000000 Binary files a/packages/rn-tester/IntegrationTests/blue_square.png and /dev/null differ diff --git a/packages/rn-tester/IntegrationTests/launchWebSocketServer.sh b/packages/rn-tester/IntegrationTests/launchWebSocketServer.sh deleted file mode 100755 index cc736a5ceffd42..00000000000000 --- a/packages/rn-tester/IntegrationTests/launchWebSocketServer.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash -# 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. - -THIS_DIR=$(cd -P "$(dirname "$(readlink "${BASH_SOURCE[0]}" || echo "${BASH_SOURCE[0]}")")" && pwd) -pushd "$THIS_DIR" || exit -./websocket_integration_test_server.js -popd || exit - -echo "Process terminated." diff --git a/packages/rn-tester/IntegrationTests/red_square.png b/packages/rn-tester/IntegrationTests/red_square.png deleted file mode 100644 index 0977a3e8cf337e..00000000000000 Binary files a/packages/rn-tester/IntegrationTests/red_square.png and /dev/null differ diff --git a/packages/rn-tester/IntegrationTests/websocket_integration_test_server.js b/packages/rn-tester/IntegrationTests/websocket_integration_test_server.js deleted file mode 100755 index 33f81521640c67..00000000000000 --- a/packages/rn-tester/IntegrationTests/websocket_integration_test_server.js +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env node -/** - * 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. - * - * @flow strict-local - * @format - */ - -'use strict'; - -/* eslint-env node */ - -const WebSocket = require('ws'); - -console.log(`\ -WebSocket integration test server - -This will send each incoming message back, with the string '_response' appended. -An incoming message of 'exit' will shut down the server. - -`); - -const server = new WebSocket.Server({port: 5555}); -server.on('connection', ws => { - ws.on('message', message => { - console.log('Received message:', message); - if (message === 'exit') { - console.log('WebSocket integration test server exit'); - process.exit(0); - } - ws.send(String(message) + '_response'); - }); - - ws.send('hello'); -}); diff --git a/packages/rn-tester/Podfile b/packages/rn-tester/Podfile index 7e723ec52341e6..4322e021db10c4 100644 --- a/packages/rn-tester/Podfile +++ b/packages/rn-tester/Podfile @@ -67,17 +67,6 @@ target 'RNTester' do pods('RNTester') end -target 'RNTesterUnitTests' do - pods('RNTesterUnitTests') - pod 'React-RCTTest', :path => "./RCTTest" - pod 'OCMock', '~> 3.9.1' -end - -target 'RNTesterIntegrationTests' do - pods('RNTesterIntegrationTests') - pod 'React-RCTTest', :path => "./RCTTest" -end - post_install do |installer| react_native_post_install(installer, @prefix_path, :mac_catalyst_enabled => false) end diff --git a/packages/rn-tester/RCTTest/FBSnapshotTestCase/FBSnapshotTestCase.h b/packages/rn-tester/RCTTest/FBSnapshotTestCase/FBSnapshotTestCase.h deleted file mode 100644 index 327e3972d97406..00000000000000 --- a/packages/rn-tester/RCTTest/FBSnapshotTestCase/FBSnapshotTestCase.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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 - -#import - -#import - -#ifndef FB_REFERENCE_IMAGE_DIR -#define FB_REFERENCE_IMAGE_DIR "\"$(SOURCE_ROOT)/$(PROJECT_NAME)Tests/ReferenceImages\"" -#endif - -/** - The base class of view snapshotting tests. If you have small UI component, it's often easier to configure it in a test - and compare an image of the view to a reference image that write lots of complex layout-code tests. - - In order to flip the tests in your subclass to record the reference images set `recordMode` to YES before calling - -[super setUp]. - */ -@interface FBSnapshotTestCase : XCTestCase - -/** - When YES, the test macros will save reference images, rather than performing an actual test. - */ -@property (readwrite, nonatomic, assign) BOOL recordMode; - -/** - Performs the comparisons or records a snapshot of the view if recordMode is YES. - @param view The view to snapshot - @param referenceImagesDirectory The directory in which reference images are stored. - @param identifier An optional identifier, used if there are multiple snapshot tests in a given -test method. - @param error An error to log in an XCTAssert() macro if the method fails (missing reference image, images differ, etc). - @returns YES if the comparison (or saving of the reference image) succeeded. - */ -- (BOOL)compareSnapshotOfView:(UIView *)view - referenceImagesDirectory:(NSString *)referenceImagesDirectory - identifier:(NSString *)identifier - error:(NSError **)errorPtr; - -@end diff --git a/packages/rn-tester/RCTTest/FBSnapshotTestCase/FBSnapshotTestCase.m b/packages/rn-tester/RCTTest/FBSnapshotTestCase/FBSnapshotTestCase.m deleted file mode 100644 index 9e5a14c2c3e21f..00000000000000 --- a/packages/rn-tester/RCTTest/FBSnapshotTestCase/FBSnapshotTestCase.m +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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 "FBSnapshotTestCase.h" - -#import "FBSnapshotTestController.h" - -@interface FBSnapshotTestCase () - -@property (readwrite, nonatomic, retain) FBSnapshotTestController *snapshotController; - -@end - -@implementation FBSnapshotTestCase - -- (void)setUp -{ - [super setUp]; - self.snapshotController = [[FBSnapshotTestController alloc] initWithTestName:NSStringFromClass([self class])]; -} - -- (void)tearDown -{ - self.snapshotController = nil; - [super tearDown]; -} - -- (BOOL)recordMode -{ - return self.snapshotController.recordMode; -} - -- (void)setRecordMode:(BOOL)recordMode -{ - self.snapshotController.recordMode = recordMode; -} - -- (BOOL)compareSnapshotOfView:(UIView *)view - referenceImagesDirectory:(NSString *)referenceImagesDirectory - identifier:(NSString *)identifier - error:(NSError **)errorPtr -{ - _snapshotController.referenceImagesDirectory = referenceImagesDirectory; - return [_snapshotController compareSnapshotOfView:view - selector:self.invocation.selector - identifier:identifier - error:errorPtr]; -} - -@end diff --git a/packages/rn-tester/RCTTest/FBSnapshotTestCase/FBSnapshotTestController.h b/packages/rn-tester/RCTTest/FBSnapshotTestCase/FBSnapshotTestController.h deleted file mode 100644 index f220d0fd6fd057..00000000000000 --- a/packages/rn-tester/RCTTest/FBSnapshotTestCase/FBSnapshotTestController.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * 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 -#import - -typedef NS_ENUM(NSInteger, FBSnapshotTestControllerErrorCode) { - FBSnapshotTestControllerErrorCodeUnknown, - FBSnapshotTestControllerErrorCodeNeedsRecord, - FBSnapshotTestControllerErrorCodePNGCreationFailed, - FBSnapshotTestControllerErrorCodeImagesDifferentSizes, - FBSnapshotTestControllerErrorCodeImagesDifferent, -}; -/** - Errors returned by the methods of FBSnapshotTestController use this domain. - */ -extern NSString *const FBSnapshotTestControllerErrorDomain; - -/** - Errors returned by the methods of FBSnapshotTestController sometimes contain this key in the `userInfo` dictionary. - */ -extern NSString *const FBReferenceImageFilePathKey; - -/** - Provides the heavy-lifting for FBSnapshotTestCase. It loads and saves images, along with performing the actual pixel- - by-pixel comparison of images. - Instances are initialized with the test class, and directories to read and write to. - */ -@interface FBSnapshotTestController : NSObject - -/** - Record snapshots. - **/ -@property (readwrite, nonatomic, assign) BOOL recordMode; - -/** - @param testClass The subclass of FBSnapshotTestCase that is using this controller. - @returns An instance of FBSnapshotTestController. - */ -- (id)initWithTestClass:(Class)testClass; - -/** - Designated initializer. - @param testName The name of the tests. - @returns An instance of FBSnapshotTestController. - */ -- (id)initWithTestName:(NSString *)testName; - -/** - Performs the comparison of the view. - @param view The view to snapshot. - @param selector selector - @param identifier An optional identifier, used is there are multiple snapshot tests in a given -test method. - @param errorPtr An error to log in an XCTAssert() macro if the method fails (missing reference image, images differ, - etc). - @returns YES if the comparison (or saving of the reference image) succeeded. - */ -- (BOOL)compareSnapshotOfView:(UIView *)view - selector:(SEL)selector - identifier:(NSString *)identifier - error:(NSError **)errorPtr; - -/** - The directory in which reference images are stored. - */ -@property (readwrite, nonatomic, copy) NSString *referenceImagesDirectory; - -/** - Loads a reference image. - @param selector The test method being run. - @param identifier The optional identifier, used when multiple images are tested in a single -test method. - @param error An error, if this methods returns nil, the error will be something useful. - @returns An image. - */ -- (UIImage *)referenceImageForSelector:(SEL)selector identifier:(NSString *)identifier error:(NSError **)error; - -/** - Saves a reference image. - @param selector The test method being run. - @param identifier The optional identifier, used when multiple images are tested in a single -test method. - @param errorPtr An error, if this methods returns NO, the error will be something useful. - @returns An image. - */ -- (BOOL)saveReferenceImage:(UIImage *)image - selector:(SEL)selector - identifier:(NSString *)identifier - error:(NSError **)errorPtr; - -/** - Performs a pixel-by-pixel comparison of the two images. - @param referenceImage The reference (correct) image. - @param image The image to test against the reference. - @param errorPtr An error that indicates why the comparison failed if it does. - @returns YES if the comparison succeeded and the images are the same. - */ -- (BOOL)compareReferenceImage:(UIImage *)referenceImage toImage:(UIImage *)image error:(NSError **)errorPtr; - -/** - Saves the reference image and the test image to `failedOutputDirectory`. - @param referenceImage The reference (correct) image. - @param testImage The image to test against the reference. - @param selector The test method being run. - @param identifier The optional identifier, used when multiple images are tested in a single -test method. - @param errorPtr An error that indicates why the comparison failed if it does. - @returns YES if the save succeeded. - */ -- (BOOL)saveFailedReferenceImage:(UIImage *)referenceImage - testImage:(UIImage *)testImage - selector:(SEL)selector - identifier:(NSString *)identifier - error:(NSError **)errorPtr; -@end diff --git a/packages/rn-tester/RCTTest/FBSnapshotTestCase/FBSnapshotTestController.m b/packages/rn-tester/RCTTest/FBSnapshotTestCase/FBSnapshotTestController.m deleted file mode 100644 index 261def2c6c7711..00000000000000 --- a/packages/rn-tester/RCTTest/FBSnapshotTestCase/FBSnapshotTestController.m +++ /dev/null @@ -1,337 +0,0 @@ -/* - * 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 "FBSnapshotTestController.h" - -#import - -#import - -#import "UIImage+Compare.h" -#import "UIImage+Diff.h" - -NSString *const FBSnapshotTestControllerErrorDomain = @"FBSnapshotTestControllerErrorDomain"; - -NSString *const FBReferenceImageFilePathKey = @"FBReferenceImageFilePathKey"; - -typedef struct RGBAPixel { - char r; - char g; - char b; - char a; -} RGBAPixel; - -@interface FBSnapshotTestController () - -@property (readonly, nonatomic, copy) NSString *testName; - -@end - -@implementation FBSnapshotTestController { - NSFileManager *_fileManager; -} - -#pragma mark - Lifecycle - -- (instancetype)initWithTestClass:(Class)testClass -{ - return [self initWithTestName:NSStringFromClass(testClass)]; -} - -- (instancetype)initWithTestName:(NSString *)testName -{ - if ((self = [super init])) { - _testName = [testName copy]; - _fileManager = [NSFileManager new]; - } - return self; -} - -#pragma mark - Properties - -- (NSString *)description -{ - return [NSString stringWithFormat:@"%@ %@", [super description], _referenceImagesDirectory]; -} - -#pragma mark - Public API - -- (UIImage *)referenceImageForSelector:(SEL)selector identifier:(NSString *)identifier error:(NSError **)errorPtr -{ - NSString *filePath = [self _referenceFilePathForSelector:selector identifier:identifier]; - UIImage *image = [UIImage imageWithContentsOfFile:filePath]; - if (nil == image && NULL != errorPtr) { - BOOL exists = [_fileManager fileExistsAtPath:filePath]; - if (!exists) { - *errorPtr = [NSError errorWithDomain:FBSnapshotTestControllerErrorDomain - code:FBSnapshotTestControllerErrorCodeNeedsRecord - userInfo:@{ - FBReferenceImageFilePathKey : filePath, - NSLocalizedDescriptionKey : @"Unable to load reference image.", - NSLocalizedFailureReasonErrorKey : - @"Reference image not found. You need to run the test in record mode", - }]; - } else { - *errorPtr = [NSError errorWithDomain:FBSnapshotTestControllerErrorDomain - code:FBSnapshotTestControllerErrorCodeUnknown - userInfo:nil]; - } - } - return image; -} - -- (BOOL)saveReferenceImage:(UIImage *)image - selector:(SEL)selector - identifier:(NSString *)identifier - error:(NSError **)errorPtr -{ - BOOL didWrite = NO; - if (nil != image) { - NSString *filePath = [self _referenceFilePathForSelector:selector identifier:identifier]; - NSData *pngData = UIImagePNGRepresentation(image); - if (nil != pngData) { - NSError *creationError = nil; - BOOL didCreateDir = [_fileManager createDirectoryAtPath:[filePath stringByDeletingLastPathComponent] - withIntermediateDirectories:YES - attributes:nil - error:&creationError]; - if (!didCreateDir) { - if (NULL != errorPtr) { - *errorPtr = creationError; - } - return NO; - } - didWrite = [pngData writeToFile:filePath options:NSDataWritingAtomic error:errorPtr]; - if (didWrite) { - NSLog(@"Reference image save at: %@", filePath); - } - } else { - if (nil != errorPtr) { - *errorPtr = [NSError errorWithDomain:FBSnapshotTestControllerErrorDomain - code:FBSnapshotTestControllerErrorCodePNGCreationFailed - userInfo:@{ - FBReferenceImageFilePathKey : filePath, - }]; - } - } - } - return didWrite; -} - -- (BOOL)saveFailedReferenceImage:(UIImage *)referenceImage - testImage:(UIImage *)testImage - selector:(SEL)selector - identifier:(NSString *)identifier - error:(NSError **)errorPtr -{ - NSData *referencePNGData = UIImagePNGRepresentation(referenceImage); - NSData *testPNGData = UIImagePNGRepresentation(testImage); - - NSString *referencePath = [self _failedFilePathForSelector:selector - identifier:identifier - fileNameType:FBTestSnapshotFileNameTypeFailedReference]; - - NSError *creationError = nil; - BOOL didCreateDir = [_fileManager createDirectoryAtPath:[referencePath stringByDeletingLastPathComponent] - withIntermediateDirectories:YES - attributes:nil - error:&creationError]; - if (!didCreateDir) { - if (NULL != errorPtr) { - *errorPtr = creationError; - } - return NO; - } - - if (![referencePNGData writeToFile:referencePath options:NSDataWritingAtomic error:errorPtr]) { - return NO; - } - - NSString *testPath = [self _failedFilePathForSelector:selector - identifier:identifier - fileNameType:FBTestSnapshotFileNameTypeFailedTest]; - - if (![testPNGData writeToFile:testPath options:NSDataWritingAtomic error:errorPtr]) { - return NO; - } - - NSString *diffPath = [self _failedFilePathForSelector:selector - identifier:identifier - fileNameType:FBTestSnapshotFileNameTypeFailedTestDiff]; - - UIImage *diffImage = [referenceImage diffWithImage:testImage]; - NSData *diffImageData = UIImagePNGRepresentation(diffImage); - - if (![diffImageData writeToFile:diffPath options:NSDataWritingAtomic error:errorPtr]) { - return NO; - } - - NSLog( - @"If you have Kaleidoscope installed you can run this command to see an image diff:\n" - @"ksdiff \"%@\" \"%@\"", - referencePath, - testPath); - - return YES; -} - -- (BOOL)compareReferenceImage:(UIImage *)referenceImage toImage:(UIImage *)image error:(NSError **)errorPtr -{ - if (CGSizeEqualToSize(referenceImage.size, image.size)) { - BOOL imagesEqual = [referenceImage compareWithImage:image]; - if (NULL != errorPtr) { - *errorPtr = [NSError errorWithDomain:FBSnapshotTestControllerErrorDomain - code:FBSnapshotTestControllerErrorCodeImagesDifferent - userInfo:@{ - NSLocalizedDescriptionKey : @"Images different", - }]; - } - return imagesEqual; - } - if (NULL != errorPtr) { - *errorPtr = [NSError - errorWithDomain:FBSnapshotTestControllerErrorDomain - code:FBSnapshotTestControllerErrorCodeImagesDifferentSizes - userInfo:@{ - NSLocalizedDescriptionKey : @"Images different sizes", - NSLocalizedFailureReasonErrorKey : [NSString stringWithFormat:@"referenceImage:%@, image:%@", - NSStringFromCGSize(referenceImage.size), - NSStringFromCGSize(image.size)], - }]; - } - return NO; -} - -#pragma mark - Private API - -typedef NS_ENUM(NSInteger, FBTestSnapshotFileNameType) { - FBTestSnapshotFileNameTypeReference, - FBTestSnapshotFileNameTypeFailedReference, - FBTestSnapshotFileNameTypeFailedTest, - FBTestSnapshotFileNameTypeFailedTestDiff, -}; - -- (NSString *)_fileNameForSelector:(SEL)selector - identifier:(NSString *)identifier - fileNameType:(FBTestSnapshotFileNameType)fileNameType -{ - NSString *fileName = nil; - switch (fileNameType) { - case FBTestSnapshotFileNameTypeFailedReference: - fileName = @"reference_"; - break; - case FBTestSnapshotFileNameTypeFailedTest: - fileName = @"failed_"; - break; - case FBTestSnapshotFileNameTypeFailedTestDiff: - fileName = @"diff_"; - break; - default: - fileName = @""; - break; - } - fileName = [fileName stringByAppendingString:NSStringFromSelector(selector)]; - if (0 < identifier.length) { - fileName = [fileName stringByAppendingFormat:@"_%@", identifier]; - } - - UITraitCollection *currentTraitCollection = [UITraitCollection currentTraitCollection]; - if (currentTraitCollection.displayScale > 1.0) { - fileName = [fileName stringByAppendingFormat:@"@%.fx", currentTraitCollection.displayScale]; - } - fileName = [fileName stringByAppendingPathExtension:@"png"]; - return fileName; -} - -- (NSString *)_referenceFilePathForSelector:(SEL)selector identifier:(NSString *)identifier -{ - NSString *fileName = [self _fileNameForSelector:selector - identifier:identifier - fileNameType:FBTestSnapshotFileNameTypeReference]; - NSString *filePath = [_referenceImagesDirectory stringByAppendingPathComponent:_testName]; - filePath = [filePath stringByAppendingPathComponent:fileName]; - return filePath; -} - -- (NSString *)_failedFilePathForSelector:(SEL)selector - identifier:(NSString *)identifier - fileNameType:(FBTestSnapshotFileNameType)fileNameType -{ - NSString *fileName = [self _fileNameForSelector:selector identifier:identifier fileNameType:fileNameType]; - NSString *folderPath = NSTemporaryDirectory(); - if (getenv("IMAGE_DIFF_DIR")) { - folderPath = @(getenv("IMAGE_DIFF_DIR")); - } - NSString *filePath = [folderPath stringByAppendingPathComponent:_testName]; - filePath = [filePath stringByAppendingPathComponent:fileName]; - return filePath; -} - -- (BOOL)compareSnapshotOfView:(id)view - selector:(SEL)selector - identifier:(NSString *)identifier - error:(NSError **)errorPtr -{ - if (self.recordMode) { - return [self _recordSnapshotOfView:view selector:selector identifier:identifier error:errorPtr]; - } else { - return [self _performPixelComparisonWithView:view selector:selector identifier:identifier error:errorPtr]; - } -} - -#pragma mark - Private API - -- (BOOL)_performPixelComparisonWithView:(UIView *)view - selector:(SEL)selector - identifier:(NSString *)identifier - error:(NSError **)errorPtr -{ - UIImage *referenceImage = [self referenceImageForSelector:selector identifier:identifier error:errorPtr]; - if (nil != referenceImage) { - UIImage *snapshot = [self _snapshotView:view]; - BOOL imagesSame = [self compareReferenceImage:referenceImage toImage:snapshot error:errorPtr]; - if (!imagesSame) { - [self saveFailedReferenceImage:referenceImage - testImage:snapshot - selector:selector - identifier:identifier - error:errorPtr]; - } - return imagesSame; - } - return NO; -} - -- (BOOL)_recordSnapshotOfView:(UIView *)view - selector:(SEL)selector - identifier:(NSString *)identifier - error:(NSError **)errorPtr -{ - UIImage *snapshot = [self _snapshotView:view]; - return [self saveReferenceImage:snapshot selector:selector identifier:identifier error:errorPtr]; -} - -- (UIImage *)_snapshotView:(UIView *)view -{ - [view layoutIfNeeded]; - - CGRect bounds = view.bounds; - - NSAssert1(CGRectGetWidth(bounds), @"Zero width for view %@", view); - NSAssert1(CGRectGetHeight(bounds), @"Zero height for view %@", view); - - UIGraphicsImageRendererFormat *const rendererFormat = [UIGraphicsImageRendererFormat defaultFormat]; - UIGraphicsImageRenderer *const renderer = [[UIGraphicsImageRenderer alloc] initWithSize:bounds.size - format:rendererFormat]; - - return [renderer imageWithActions:^(UIGraphicsImageRendererContext *_Nonnull context) { - BOOL success = [view drawViewHierarchyInRect:bounds afterScreenUpdates:YES]; - NSAssert1(success, @"Could not create snapshot for view %@", view); - }]; -} - -@end diff --git a/packages/rn-tester/RCTTest/FBSnapshotTestCase/UIImage+Compare.h b/packages/rn-tester/RCTTest/FBSnapshotTestCase/UIImage+Compare.h deleted file mode 100644 index e84bbc6ea99592..00000000000000 --- a/packages/rn-tester/RCTTest/FBSnapshotTestCase/UIImage+Compare.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * 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 - -@interface UIImage (Compare) - -- (BOOL)compareWithImage:(UIImage *)image; - -@end diff --git a/packages/rn-tester/RCTTest/FBSnapshotTestCase/UIImage+Compare.m b/packages/rn-tester/RCTTest/FBSnapshotTestCase/UIImage+Compare.m deleted file mode 100644 index e46d975ea0b80b..00000000000000 --- a/packages/rn-tester/RCTTest/FBSnapshotTestCase/UIImage+Compare.m +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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 "UIImage+Compare.h" - -@implementation UIImage (Compare) - -- (BOOL)compareWithImage:(UIImage *)image -{ - NSAssert(CGSizeEqualToSize(self.size, image.size), @"Images must be same size."); - - // The images have the equal size, so we could use the smallest amount of bytes because of byte padding - size_t minBytesPerRow = MIN(CGImageGetBytesPerRow(self.CGImage), CGImageGetBytesPerRow(image.CGImage)); - size_t referenceImageSizeBytes = CGImageGetHeight(self.CGImage) * minBytesPerRow; - void *referenceImagePixels = calloc(1, referenceImageSizeBytes); - void *imagePixels = calloc(1, referenceImageSizeBytes); - - if (!referenceImagePixels || !imagePixels) { - free(referenceImagePixels); - free(imagePixels); - return NO; - } - - CGContextRef referenceImageContext = CGBitmapContextCreate( - referenceImagePixels, - CGImageGetWidth(self.CGImage), - CGImageGetHeight(self.CGImage), - CGImageGetBitsPerComponent(self.CGImage), - minBytesPerRow, - CGImageGetColorSpace(self.CGImage), - (CGBitmapInfo)kCGImageAlphaPremultipliedLast); - CGContextRef imageContext = CGBitmapContextCreate( - imagePixels, - CGImageGetWidth(image.CGImage), - CGImageGetHeight(image.CGImage), - CGImageGetBitsPerComponent(image.CGImage), - minBytesPerRow, - CGImageGetColorSpace(image.CGImage), - (CGBitmapInfo)kCGImageAlphaPremultipliedLast); - - CGFloat scaleFactor = [UITraitCollection currentTraitCollection].displayScale; - CGContextScaleCTM(referenceImageContext, scaleFactor, scaleFactor); - CGContextScaleCTM(imageContext, scaleFactor, scaleFactor); - - if (!referenceImageContext || !imageContext) { - CGContextRelease(referenceImageContext); - CGContextRelease(imageContext); - free(referenceImagePixels); - free(imagePixels); - return NO; - } - - CGContextDrawImage(referenceImageContext, CGRectMake(0.0f, 0.0f, self.size.width, self.size.height), self.CGImage); - CGContextDrawImage(imageContext, CGRectMake(0.0f, 0.0f, image.size.width, image.size.height), image.CGImage); - CGContextRelease(referenceImageContext); - CGContextRelease(imageContext); - - BOOL imageEqual = (memcmp(referenceImagePixels, imagePixels, referenceImageSizeBytes) == 0); - free(referenceImagePixels); - free(imagePixels); - return imageEqual; -} - -@end diff --git a/packages/rn-tester/RCTTest/FBSnapshotTestCase/UIImage+Diff.h b/packages/rn-tester/RCTTest/FBSnapshotTestCase/UIImage+Diff.h deleted file mode 100644 index 4bf6f527846ec6..00000000000000 --- a/packages/rn-tester/RCTTest/FBSnapshotTestCase/UIImage+Diff.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * 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 - -@interface UIImage (Diff) - -- (UIImage *)diffWithImage:(UIImage *)image; - -@end diff --git a/packages/rn-tester/RCTTest/FBSnapshotTestCase/UIImage+Diff.m b/packages/rn-tester/RCTTest/FBSnapshotTestCase/UIImage+Diff.m deleted file mode 100644 index 178f988fa595c3..00000000000000 --- a/packages/rn-tester/RCTTest/FBSnapshotTestCase/UIImage+Diff.m +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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 "UIImage+Diff.h" - -@implementation UIImage (Diff) - -- (UIImage *)diffWithImage:(UIImage *)image -{ - if (!image) { - return nil; - } - CGSize imageSize = CGSizeMake(MAX(self.size.width, image.size.width), MAX(self.size.height, image.size.height)); - - UIGraphicsImageRendererFormat *const rendererFormat = [UIGraphicsImageRendererFormat defaultFormat]; - rendererFormat.opaque = YES; - UIGraphicsImageRenderer *const renderer = [[UIGraphicsImageRenderer alloc] initWithSize:imageSize - format:rendererFormat]; - - return [renderer imageWithActions:^(UIGraphicsImageRendererContext *_Nonnull rendererContext) { - const CGContextRef context = rendererContext.CGContext; - [self drawInRect:CGRectMake(0, 0, self.size.width, self.size.height)]; - CGContextSetAlpha(context, 0.5f); - CGContextBeginTransparencyLayer(context, NULL); - [image drawInRect:CGRectMake(0, 0, image.size.width, image.size.height)]; - CGContextSetBlendMode(context, kCGBlendModeDifference); - CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor); - CGContextFillRect(context, CGRectMake(0, 0, self.size.width, self.size.height)); - CGContextEndTransparencyLayer(context); - }]; -} - -@end diff --git a/packages/rn-tester/RCTTest/RCTSnapshotManager.h b/packages/rn-tester/RCTTest/RCTSnapshotManager.h deleted file mode 100644 index 4cd67c2a142506..00000000000000 --- a/packages/rn-tester/RCTTest/RCTSnapshotManager.h +++ /dev/null @@ -1,12 +0,0 @@ -/* - * 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 - -@interface RCTSnapshotManager : RCTViewManager - -@end diff --git a/packages/rn-tester/RCTTest/RCTSnapshotManager.m b/packages/rn-tester/RCTTest/RCTSnapshotManager.m deleted file mode 100644 index 7b17622015af6c..00000000000000 --- a/packages/rn-tester/RCTTest/RCTSnapshotManager.m +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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 "RCTSnapshotManager.h" - -@interface RCTSnapshotView : UIView - -@property (nonatomic, copy) RCTDirectEventBlock onSnapshotReady; -@property (nonatomic, copy) NSString *testIdentifier; - -@end - -@implementation RCTSnapshotView - -- (void)setTestIdentifier:(NSString *)testIdentifier -{ - if (![_testIdentifier isEqualToString:testIdentifier]) { - _testIdentifier = [testIdentifier copy]; - dispatch_async(dispatch_get_main_queue(), ^{ - if (self.onSnapshotReady) { - self.onSnapshotReady(@{@"testIdentifier" : self.testIdentifier}); - } - }); - } -} - -@end - -@implementation RCTSnapshotManager - -RCT_EXPORT_MODULE() - -- (UIView *)view -{ - return [RCTSnapshotView new]; -} - -RCT_EXPORT_VIEW_PROPERTY(testIdentifier, NSString) -RCT_EXPORT_VIEW_PROPERTY(onSnapshotReady, RCTDirectEventBlock) - -@end diff --git a/packages/rn-tester/RCTTest/RCTSnapshotNativeComponent.js b/packages/rn-tester/RCTTest/RCTSnapshotNativeComponent.js deleted file mode 100644 index f1a6e7508072cb..00000000000000 --- a/packages/rn-tester/RCTTest/RCTSnapshotNativeComponent.js +++ /dev/null @@ -1,34 +0,0 @@ -/** - * 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. - * - * @format - * @flow strict-local - */ - -'use strict'; - -import type { - HostComponent, - NativeSyntheticEvent, - ViewProps, -} from 'react-native'; - -const {requireNativeComponent} = require('react-native'); - -type SnapshotReadyEvent = NativeSyntheticEvent< - $ReadOnly<{testIdentifier: string, ...}>, ->; - -type NativeProps = $ReadOnly<{ - ...ViewProps, - onSnapshotReady?: ?(event: SnapshotReadyEvent) => mixed, - testIdentifier?: ?string, -}>; - -const RCTSnapshotNativeComponent: HostComponent = - requireNativeComponent('RCTSnapshot'); - -module.exports = RCTSnapshotNativeComponent; diff --git a/packages/rn-tester/RCTTest/RCTTestModule.h b/packages/rn-tester/RCTTest/RCTTestModule.h deleted file mode 100644 index 5f60be764db2e0..00000000000000 --- a/packages/rn-tester/RCTTest/RCTTestModule.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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 - -#import -#import - -typedef NS_ENUM(NSInteger, RCTTestStatus) { RCTTestStatusPending = 0, RCTTestStatusPassed, RCTTestStatusFailed }; - -@class FBSnapshotTestController; - -@interface RCTTestModule : NSObject - -/** - * The snapshot test controller for this module. - */ -@property (nonatomic, strong) FBSnapshotTestController *controller; - -/** - * This is the view to be snapshotted. - */ -@property (nonatomic, strong) UIView *view; - -/** - * This is used to give meaningful names to snapshot image files. - */ -@property (nonatomic, assign) SEL testSelector; - -/** - * This is polled while running the runloop until true. - */ -@property (nonatomic, readonly) RCTTestStatus status; - -@property (nonatomic, copy) NSString *testSuffix; - -@end diff --git a/packages/rn-tester/RCTTest/RCTTestModule.mm b/packages/rn-tester/RCTTest/RCTTestModule.mm deleted file mode 100644 index ab797d55f893e0..00000000000000 --- a/packages/rn-tester/RCTTest/RCTTestModule.mm +++ /dev/null @@ -1,178 +0,0 @@ -/* - * 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 "RCTTestModule.h" - -#import -#import -#import -#import -#import - -#import "FBSnapshotTestController.h" - -#import "RCTTestPlugins.h" - -@protocol NativeTestModuleSpec - -- (void)markTestCompleted; -- (void)markTestPassed:(BOOL)success; -- (void)verifySnapshot:(RCTResponseSenderBlock)callback; - -@end - -namespace facebook { -namespace react { -/** - * ObjC++ class for module 'TestModule' - */ - -class JSI_EXPORT NativeTestModuleSpecJSI : public ObjCTurboModule { - public: - NativeTestModuleSpecJSI(const ObjCTurboModule::InitParams ¶ms); -}; -} // namespace react -} // namespace facebook - -namespace facebook { -namespace react { - -static facebook::jsi::Value __hostFunction_NativeTestModuleSpecJSI_markTestCompleted( - facebook::jsi::Runtime &rt, - TurboModule &turboModule, - const facebook::jsi::Value *args, - size_t count) -{ - return static_cast(turboModule) - .invokeObjCMethod(rt, VoidKind, "markTestCompleted", @selector(markTestCompleted), args, count); -} - -static facebook::jsi::Value __hostFunction_NativeTestModuleSpecJSI_markTestPassed( - facebook::jsi::Runtime &rt, - TurboModule &turboModule, - const facebook::jsi::Value *args, - size_t count) -{ - return static_cast(turboModule) - .invokeObjCMethod(rt, VoidKind, "markTestPassed", @selector(markTestPassed:), args, count); -} - -static facebook::jsi::Value __hostFunction_NativeTestModuleSpecJSI_verifySnapshot( - facebook::jsi::Runtime &rt, - TurboModule &turboModule, - const facebook::jsi::Value *args, - size_t count) -{ - return static_cast(turboModule) - .invokeObjCMethod(rt, VoidKind, "verifySnapshot", @selector(verifySnapshot:), args, count); -} - -NativeTestModuleSpecJSI::NativeTestModuleSpecJSI(const ObjCTurboModule::InitParams ¶ms) : ObjCTurboModule(params) -{ - methodMap_["markTestCompleted"] = MethodMetadata{0, __hostFunction_NativeTestModuleSpecJSI_markTestCompleted}; - - methodMap_["markTestPassed"] = MethodMetadata{1, __hostFunction_NativeTestModuleSpecJSI_markTestPassed}; - - methodMap_["verifySnapshot"] = MethodMetadata{1, __hostFunction_NativeTestModuleSpecJSI_verifySnapshot}; -} - -} // namespace react -} // namespace facebook - -@interface RCTTestModule () -@end - -@implementation RCTTestModule { - NSMutableDictionary *_snapshotCounter; -} - -@synthesize bridge = _bridge; -@synthesize moduleRegistry = _moduleRegistry; - -RCT_EXPORT_MODULE() - -- (dispatch_queue_t)methodQueue -{ - return _bridge.uiManager.methodQueue; -} - -RCT_EXPORT_METHOD(verifySnapshot : (RCTResponseSenderBlock)callback) -{ - RCTAssert(_controller != nil, @"No snapshot controller configured."); - - [_bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary *viewRegistry) { - NSString *testName = NSStringFromSelector(self->_testSelector); - if (!self->_snapshotCounter) { - self->_snapshotCounter = [NSMutableDictionary new]; - } - - NSNumber *counter = @([self->_snapshotCounter[testName] integerValue] + 1); - self->_snapshotCounter[testName] = counter; - - NSError *error = nil; - NSString *identifier = [counter stringValue]; - if (self->_testSuffix) { - identifier = [identifier stringByAppendingString:self->_testSuffix]; - } - BOOL success = [self->_controller compareSnapshotOfView:self->_view - selector:self->_testSelector - identifier:identifier - error:&error]; - if (!success) { - RCTLogInfo(@"Failed to verify snapshot %@ (error: %@)", identifier, error); - } - callback(@[ @(success) ]); - }]; -} - -RCT_EXPORT_METHOD(sendAppEvent : (NSString *)name body : (nullable id)body) -{ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - [[_moduleRegistry moduleForName:"EventDispatcher"] sendAppEventWithName:name body:body]; -#pragma clang diagnostic pop -} - -RCT_REMAP_METHOD(shouldResolve, shouldResolve_resolve - : (RCTPromiseResolveBlock)resolve reject - : (RCTPromiseRejectBlock)reject) -{ - resolve(@1); -} - -RCT_REMAP_METHOD(shouldReject, shouldReject_resolve - : (RCTPromiseResolveBlock)resolve reject - : (RCTPromiseRejectBlock)reject) -{ - reject(nil, nil, nil); -} - -RCT_EXPORT_METHOD(markTestCompleted) -{ - [self markTestPassed:YES]; -} - -RCT_EXPORT_METHOD(markTestPassed : (BOOL)success) -{ - [_bridge.uiManager - addUIBlock:^(__unused RCTUIManager *uiManager, __unused NSDictionary *viewRegistry) { - self->_status = success ? RCTTestStatusPassed : RCTTestStatusFailed; - }]; -} - -- (std::shared_ptr)getTurboModule: - (const facebook::react::ObjCTurboModule::InitParams &)params -{ - return std::make_shared(params); -} - -@end - -Class RCTTestModuleCls(void) -{ - return RCTTestModule.class; -} diff --git a/packages/rn-tester/RCTTest/RCTTestPlugins.h b/packages/rn-tester/RCTTest/RCTTestPlugins.h deleted file mode 100644 index 755019513d4a85..00000000000000 --- a/packages/rn-tester/RCTTest/RCTTestPlugins.h +++ /dev/null @@ -1,40 +0,0 @@ -/** - * 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. - * - * @generated by an internal plugin build system - */ - -#ifdef RN_DISABLE_OSS_PLUGIN_HEADER - -// FB Internal: FBRCTTestPlugins.h is autogenerated by the build system. -#import - -#else - -// OSS-compatibility layer - -#import - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wreturn-type-c-linkage" - -#ifdef __cplusplus -extern "C" { -#endif - -// RCTTurboModuleManagerDelegate should call this to resolve module classes. -Class RCTTestClassProvider(const char *name); - -// Lookup functions -Class RCTTestModuleCls(void) __attribute__((used)); - -#ifdef __cplusplus -} -#endif - -#pragma GCC diagnostic pop - -#endif // RN_DISABLE_OSS_PLUGIN_HEADER diff --git a/packages/rn-tester/RCTTest/RCTTestPlugins.mm b/packages/rn-tester/RCTTest/RCTTestPlugins.mm deleted file mode 100644 index aee79a0764bfef..00000000000000 --- a/packages/rn-tester/RCTTest/RCTTestPlugins.mm +++ /dev/null @@ -1,32 +0,0 @@ -/** - * 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. - * - * @generated by an internal plugin build system - */ - -#ifndef RN_DISABLE_OSS_PLUGIN_HEADER - -// OSS-compatibility layer - -#import "RCTTestPlugins.h" - -#import -#import - -Class RCTTestClassProvider(const char *name) { - static std::unordered_map sCoreModuleClassMap = { - {"TestModule", RCTTestModuleCls}, - }; - - auto p = sCoreModuleClassMap.find(name); - if (p != sCoreModuleClassMap.end()) { - auto classFunc = p->second; - return classFunc(); - } - return nil; -} - -#endif // RN_DISABLE_OSS_PLUGIN_HEADER diff --git a/packages/rn-tester/RCTTest/RCTTestRunner.h b/packages/rn-tester/RCTTest/RCTTestRunner.h deleted file mode 100644 index 5fb15bd2e3bceb..00000000000000 --- a/packages/rn-tester/RCTTest/RCTTestRunner.h +++ /dev/null @@ -1,160 +0,0 @@ -/* - * 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 - -#import - -#ifndef FB_REFERENCE_IMAGE_DIR -#define FB_REFERENCE_IMAGE_DIR "" -#endif - -#define RCT_RUN_RUNLOOP_WHILE(CONDITION) \ - { \ - NSDate *timeout = [NSDate dateWithTimeIntervalSinceNow:30]; \ - NSRunLoop *runloop = [NSRunLoop mainRunLoop]; \ - while ((CONDITION)) { \ - [runloop runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.01]]; \ - if ([timeout timeIntervalSinceNow] <= 0) { \ - XCTFail(@"Runloop timed out before condition was met"); \ - break; \ - } \ - } \ - } - -/** - * Use the RCTInitRunnerForApp macro for typical usage. See FBSnapshotTestCase.h for more information - * on how to configure the snapshotting system. - */ -#define RCTInitRunnerForApp(app__, moduleProvider__, scriptURL__) \ - [[RCTTestRunner alloc] initWithApp:(app__) \ - referenceDirectory:@FB_REFERENCE_IMAGE_DIR \ - moduleProvider:(moduleProvider__)scriptURL:scriptURL__] - -#define RCTInitRunnerForAppWithDelegate(app__, bridgeDelegate__) \ - [[RCTTestRunner alloc] initWithApp:(app__) \ - referenceDirectory:@FB_REFERENCE_IMAGE_DIR \ - bridgeDelegate:(bridgeDelegate__)] - -@protocol RCTBridgeModule; -@class RCTBridge; - -@class RCTRootView; - -@interface RCTTestRunner : NSObject - -/** - * Controls the mode snapshots are run in. If set to true, new snapshots are written to disk, - * otherwise, the UI will be compared to the existing snapshot. - */ -@property (nonatomic, assign) BOOL recordMode; - -@property (nonatomic, assign, readwrite) BOOL useBundler; - -@property (nonatomic, assign, readwrite) BOOL useJSDebugger; - -@property (nonatomic, copy) NSString *testSuffix; - -@property (nonatomic, readonly) NSURL *scriptURL; - -/** - * Initialize a runner. It's recommended that you use the RCTInitRunnerForApp - * macro instead of calling this directly. - * - * @param app The path to the app bundle without suffixes, e.g. IntegrationTests/IntegrationTestsApp - * @param referenceDirectory The path for snapshot references images. - * @param block A block that returns an array of extra modules to be used by the test runner. - * @param scriptURL URL to the JS bundle to use. - * @param bridgeDelegate Custom delegate for bridge activities. - */ -- (instancetype)initWithApp:(NSString *)app - referenceDirectory:(NSString *)referenceDirectory - moduleProvider:(RCTBridgeModuleListProvider)block - scriptURL:(NSURL *)scriptURL - bridgeDelegate:(id)bridgeDelegate NS_DESIGNATED_INITIALIZER; - -- (instancetype)initWithApp:(NSString *)app - referenceDirectory:(NSString *)referenceDirectory - moduleProvider:(RCTBridgeModuleListProvider)block - scriptURL:(NSURL *)scriptURL; - -- (instancetype)initWithApp:(NSString *)app - referenceDirectory:(NSString *)referenceDirectory - bridgeDelegate:(id)bridgeDelegate; - -- (NSURL *)defaultScriptURL; - -/** - * Simplest runTest function simply mounts the specified JS module with no - * initialProps and waits for it to call - * - * RCTTestModule.markTestCompleted() - * - * JS errors/exceptions and timeouts will fail the test. Snapshot tests call - * RCTTestModule.verifySnapshot whenever they want to verify what has been - * rendered (typically via requestAnimationFrame to make sure the latest state - * has been rendered in native. - * - * @param test Selector of the test, usually just `_cmd`. - * @param moduleName Name of the JS component as registered by `AppRegistry.registerComponent` in JS. - */ -- (void)runTest:(SEL)test module:(NSString *)moduleName; - -/** - * Same as runTest:, but allows for passing initialProps for providing mock data - * or requesting different behaviors, configurationBlock provides arbitrary logic for the hosting - * root view manipulation. - * - * @param test Selector of the test, usually just `_cmd`. - * @param moduleName Name of the JS component as registered by `AppRegistry.registerComponent` in JS. - * @param initialProps props that are passed into the component when rendered. - * @param configurationBlock A block that takes the hosting root view and performs arbitrary manipulation after its - * creation. - */ -- (void)runTest:(SEL)test - module:(NSString *)moduleName - initialProps:(NSDictionary *)initialProps - configurationBlock:(void (^)(RCTRootView *rootView))configurationBlock; - -/** - * Same as runTest:, but allows for passing initialProps for providing mock data - * or requesting different behaviors, configurationBlock provides arbitrary logic for the hosting - * root view manipulation, and expectErrorRegex verifies that the error you expected was thrown. - * - * @param test Selector of the test, usually just `_cmd`. - * @param moduleName Name of the JS component as registered by `AppRegistry.registerComponent` in JS. - * @param initialProps props that are passed into the component when rendered. - * @param configurationBlock A block that takes the hosting root view and performs arbitrary manipulation after its - * creation. - * @param expectErrorRegex A regex that must match the error thrown. If no error is thrown, the test fails. - */ -- (void)runTest:(SEL)test - module:(NSString *)moduleName - initialProps:(NSDictionary *)initialProps - configurationBlock:(void (^)(RCTRootView *rootView))configurationBlock - expectErrorRegex:(NSString *)expectErrorRegex; - -/** - * Same as runTest:, but allows for passing initialProps for providing mock data - * or requesting different behaviors, configurationBlock provides arbitrary logic for the hosting - * root view manipulation, and expectErrorBlock provides arbitrary - * logic for processing errors (nil will cause any error to fail the test). - * - * @param test Selector of the test, usually just `_cmd`. - * @param moduleName Name of the JS component as registered by `AppRegistry.registerComponent` in JS. - * @param initialProps props that are passed into the component when rendered. - * @param configurationBlock A block that takes the hosting root view and performs arbitrary manipulation after its - * creation. - * @param expectErrorBlock A block that takes the error message and returns NO to fail the test. - */ -- (void)runTest:(SEL)test - module:(NSString *)moduleName - initialProps:(NSDictionary *)initialProps - configurationBlock:(void (^)(RCTRootView *rootView))configurationBlock - expectErrorBlock:(BOOL (^)(NSString *error))expectErrorBlock; - -@end diff --git a/packages/rn-tester/RCTTest/RCTTestRunner.m b/packages/rn-tester/RCTTest/RCTTestRunner.m deleted file mode 100644 index f95fb987450787..00000000000000 --- a/packages/rn-tester/RCTTest/RCTTestRunner.m +++ /dev/null @@ -1,275 +0,0 @@ -/* - * 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 "RCTTestRunner.h" - -#import -#import -#import -#import -#import -#import -#import -#import - -#import "FBSnapshotTestController.h" -#import "RCTTestModule.h" - -static const NSTimeInterval kTestTimeoutSeconds = 120; - -@implementation RCTTestRunner { - FBSnapshotTestController *_testController; - RCTBridgeModuleListProvider _moduleProvider; - NSString *_appPath; - __weak id _bridgeDelegate; -} - -- (instancetype)initWithApp:(NSString *)app - referenceDirectory:(NSString *)referenceDirectory - moduleProvider:(RCTBridgeModuleListProvider)block - scriptURL:(NSURL *)scriptURL -{ - return [self initWithApp:app - referenceDirectory:referenceDirectory - moduleProvider:block - scriptURL:scriptURL - bridgeDelegate:nil]; -} - -- (instancetype)initWithApp:(NSString *)app - referenceDirectory:(NSString *)referenceDirectory - bridgeDelegate:(id)bridgeDelegate -{ - return [self initWithApp:app - referenceDirectory:referenceDirectory - moduleProvider:nil - scriptURL:nil - bridgeDelegate:bridgeDelegate]; -} - -- (instancetype)initWithApp:(NSString *)app - referenceDirectory:(NSString *)referenceDirectory - moduleProvider:(RCTBridgeModuleListProvider)block - scriptURL:(NSURL *)scriptURL - bridgeDelegate:(id)bridgeDelegate -{ - RCTAssertParam(app); - RCTAssertParam(referenceDirectory); - - if ((self = [super init])) { - if (!referenceDirectory.length) { - referenceDirectory = - [[NSBundle bundleForClass:self.class].resourcePath stringByAppendingPathComponent:@"ReferenceImages"]; - } - - NSString *sanitizedAppName = [app stringByReplacingOccurrencesOfString:@"/" withString:@"-"]; - sanitizedAppName = [sanitizedAppName stringByReplacingOccurrencesOfString:@"\\" withString:@"-"]; - _testController = [[FBSnapshotTestController alloc] initWithTestName:sanitizedAppName]; - _testController.referenceImagesDirectory = referenceDirectory; - _moduleProvider = [block copy]; - _appPath = app; - _bridgeDelegate = bridgeDelegate; - - if (scriptURL != nil) { - _scriptURL = scriptURL; - } else if (!_bridgeDelegate) { - [self updateScript]; - } - } - return self; -} - -RCT_NOT_IMPLEMENTED(-(instancetype)init) - -- (NSURL *)defaultScriptURL -{ - if (getenv("CI_USE_PACKAGER") || _useBundler) { - return [NSURL URLWithString:[NSString stringWithFormat:@"http://localhost:8081/%@.bundle?platform=%@&dev=true", - _appPath, - RCTPlatformName]]; - } else { - return [[NSBundle bundleForClass:[RCTBridge class]] URLForResource:@"main" withExtension:@"jsbundle"]; - } -} - -- (void)updateScript -{ - _scriptURL = [self defaultScriptURL]; - RCTAssert(_scriptURL != nil, @"No scriptURL set"); -} - -- (void)setRecordMode:(BOOL)recordMode -{ - _testController.recordMode = recordMode; -} - -- (BOOL)recordMode -{ - return _testController.recordMode; -} - -- (void)setUseBundler:(BOOL)useBundler -{ - _useBundler = useBundler; - [self updateScript]; -} - -- (void)runTest:(SEL)test module:(NSString *)moduleName -{ - [self runTest:test module:moduleName initialProps:nil configurationBlock:nil expectErrorBlock:nil]; -} - -- (void)runTest:(SEL)test - module:(NSString *)moduleName - initialProps:(NSDictionary *)initialProps - configurationBlock:(void (^)(RCTRootView *rootView))configurationBlock -{ - [self runTest:test - module:moduleName - initialProps:initialProps - configurationBlock:configurationBlock - expectErrorBlock:nil]; -} - -- (void)runTest:(SEL)test - module:(NSString *)moduleName - initialProps:(NSDictionary *)initialProps - configurationBlock:(void (^)(RCTRootView *rootView))configurationBlock - expectErrorRegex:(NSString *)errorRegex -{ - BOOL (^expectErrorBlock)(NSString *error) = ^BOOL(NSString *error) { - return [error rangeOfString:errorRegex options:NSRegularExpressionSearch].location != NSNotFound; - }; - - [self runTest:test - module:moduleName - initialProps:initialProps - configurationBlock:configurationBlock - expectErrorBlock:expectErrorBlock]; -} - -- (void)runTest:(SEL)test - module:(NSString *)moduleName - initialProps:(NSDictionary *)initialProps - configurationBlock:(void (^)(RCTRootView *rootView))configurationBlock - expectErrorBlock:(BOOL (^)(NSString *error))expectErrorBlock -{ - __weak RCTBridge *batchedBridge; - NSNumber *rootTag; - RCTLogFunction defaultLogFunction = RCTGetLogFunction(); - // Catch all error logs, that are equivalent to redboxes in dev mode. - __block NSMutableArray *errors = nil; - RCTSetLogFunction( - ^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) { - defaultLogFunction(level, source, fileName, lineNumber, message); - if (level >= RCTLogLevelError) { - if (errors == nil) { - errors = [NSMutableArray new]; - } - [errors addObject:message]; - } - }); - - @autoreleasepool { - RCTBridge *bridge; - if (_bridgeDelegate) { - bridge = [[RCTBridge alloc] initWithDelegate:_bridgeDelegate launchOptions:nil]; - } else { - bridge = [[RCTBridge alloc] initWithBundleURL:_scriptURL moduleProvider:_moduleProvider launchOptions:nil]; - } - batchedBridge = [bridge batchedBridge]; - - UIViewController *vc = RCTSharedApplication().delegate.window.rootViewController; - vc.view = [UIView new]; - - RCTTestModule *testModule = [bridge moduleForClass:[RCTTestModule class]]; - RCTAssert(_testController != nil, @"_testController should not be nil"); - testModule.controller = _testController; - testModule.testSelector = test; - testModule.testSuffix = _testSuffix; - - @autoreleasepool { - // The rootView needs to be deallocated after this @autoreleasepool block exits. - RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge - moduleName:moduleName - initialProperties:initialProps]; - rootView.frame = CGRectMake(0, 0, 320, 2000); // Constant size for testing on multiple devices - - rootTag = rootView.reactTag; - testModule.view = rootView; - - [vc.view addSubview:rootView]; // Add as subview so it doesn't get resized - - if (configurationBlock) { - configurationBlock(rootView); - } - - NSDate *date = [NSDate dateWithTimeIntervalSinceNow:kTestTimeoutSeconds]; - while (date.timeIntervalSinceNow > 0 && testModule.status == RCTTestStatusPending && errors == nil) { - [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; - [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; - } - - [rootView removeFromSuperview]; - testModule.view = nil; - } - - // From this point on catch only fatal errors. - RCTSetLogFunction( - ^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) { - defaultLogFunction(level, source, fileName, lineNumber, message); - if (level >= RCTLogLevelFatal) { - if (errors == nil) { - errors = [NSMutableArray new]; - } - [errors addObject:message]; - } - }); - -#if RCT_DEV - NSArray *nonLayoutSubviews = [vc.view.subviews - filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id subview, NSDictionary *bindings) { - return ![NSStringFromClass([subview class]) isEqualToString:@"_UILayoutGuide"]; - }]]; - - RCTAssert(nonLayoutSubviews.count == 0, @"There shouldn't be any other views: %@", nonLayoutSubviews); -#endif - - if (expectErrorBlock) { - RCTAssert(expectErrorBlock(errors[0]), @"Expected an error but the first one was missing or did not match."); - } else { - RCTAssert(errors == nil, @"RedBox errors: %@", errors); - RCTAssert( - testModule.status != RCTTestStatusPending, @"Test didn't finish within %0.f seconds", kTestTimeoutSeconds); - RCTAssert(testModule.status == RCTTestStatusPassed, @"Test failed"); - } - - // Wait for the rootView to be deallocated completely before invalidating the bridge. - RCTUIManager *uiManager = [bridge moduleForClass:[RCTUIManager class]]; - NSDate *date = [NSDate dateWithTimeIntervalSinceNow:5]; - while (date.timeIntervalSinceNow > 0 && [uiManager viewForReactTag:rootTag]) { - [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; - [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; - } - RCTAssert([uiManager viewForReactTag:rootTag] == nil, @"RootView should have been deallocated after removed."); - - [bridge invalidate]; - } - - // Wait for the bridge to disappear before continuing to the next test. - NSDate *invalidateTimeout = [NSDate dateWithTimeIntervalSinceNow:30]; - while (invalidateTimeout.timeIntervalSinceNow > 0 && batchedBridge != nil) { - [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; - [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; - } - RCTAssert(errors == nil, @"RedBox errors during bridge invalidation: %@", errors); - RCTAssert(batchedBridge == nil, @"Bridge should be deallocated after the test"); - - RCTSetLogFunction(defaultLogFunction); -} - -@end diff --git a/packages/rn-tester/RCTTest/React-RCTTest.podspec b/packages/rn-tester/RCTTest/React-RCTTest.podspec deleted file mode 100644 index 37fc4106f2d536..00000000000000 --- a/packages/rn-tester/RCTTest/React-RCTTest.podspec +++ /dev/null @@ -1,44 +0,0 @@ -# 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. - -require "json" - -package = JSON.parse(File.read(File.join(__dir__, "..", "..", "react-native", "package.json"))) -version = package['version'] - -source = { :git => 'https://github.com/facebook/react-native.git' } -if version == '1000.0.0' - # This is an unpublished version, use the latest commit hash of the react-native repo, which we’re presumably in. - source[:commit] = `git rev-parse HEAD`.strip if system("git rev-parse --git-dir > /dev/null 2>&1") -else - source[:tag] = "v#{version}" -end - -Pod::Spec.new do |s| - s.name = "React-RCTTest" - s.version = version - s.summary = "Tools for integration and snapshot testing." - s.homepage = "https://reactnative.dev/" - s.license = package["license"] - s.author = "Meta Platforms, Inc. and its affiliates" - s.platforms = min_supported_versions - s.compiler_flags = '-Wno-nullability-completeness' - s.source = source - s.source_files = "**/*.{h,m,mm}" - s.preserve_paths = "package.json", "LICENSE", "LICENSE-docs" - s.framework = "XCTest" - s.header_dir = "RCTTest" - s.pod_target_xcconfig = { - "USE_HEADERMAP" => "YES", - "CLANG_CXX_LANGUAGE_STANDARD" => rct_cxx_language_standard(), - } - - s.dependency "React-Core", version - s.dependency "React-CoreModules", version - s.dependency "ReactCommon/turbomodule/core", version - s.dependency "React-jsi", version - - add_rn_third_party_dependencies(s) -end diff --git a/packages/rn-tester/RNTesterIntegrationTests/Info.plist b/packages/rn-tester/RNTesterIntegrationTests/Info.plist deleted file mode 100644 index 6c40a6cd0c4af2..00000000000000 --- a/packages/rn-tester/RNTesterIntegrationTests/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - BNDL - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - - diff --git a/packages/rn-tester/RNTesterIntegrationTests/RCTLoggingTests.m b/packages/rn-tester/RNTesterIntegrationTests/RCTLoggingTests.m deleted file mode 100644 index 0d363edbe479c2..00000000000000 --- a/packages/rn-tester/RNTesterIntegrationTests/RCTLoggingTests.m +++ /dev/null @@ -1,144 +0,0 @@ -/* - * 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 - -#import -#import -#import -#import - -// Time to wait for an expected log statement to show before failing the test -const int64_t LOGGER_TIMEOUT = 10 * NSEC_PER_SEC; - -@interface RCTLoggingTests : XCTestCase - -@end - -@implementation RCTLoggingTests { - RCTBridge *_bridge; - - dispatch_semaphore_t _logSem; - RCTLogLevel _lastLogLevel; - RCTLogSource _lastLogSource; - NSString *_lastLogMessage; -} - -- (void)setUp -{ - NSURL *scriptURL; - if (getenv("CI_USE_PACKAGER")) { - NSString *app = @"IntegrationTests/IntegrationTestsApp"; - scriptURL = [NSURL URLWithString:[NSString stringWithFormat:@"http://localhost:8081/%@.bundle?platform=%@&dev=true", - app, - RCTPlatformName]]; - } else { - scriptURL = [[NSBundle bundleForClass:[RCTBridge class]] URLForResource:@"main" withExtension:@"jsbundle"]; - } - RCTAssert(scriptURL != nil, @"No scriptURL set"); - - _bridge = [[RCTBridge alloc] initWithBundleURL:scriptURL moduleProvider:NULL launchOptions:nil]; - NSDate *date = [NSDate dateWithTimeIntervalSinceNow:60]; - while (date.timeIntervalSinceNow > 0 && _bridge.loading) { - [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; - } - XCTAssertFalse(_bridge.loading); - - _logSem = dispatch_semaphore_create(0); - - // Set the log function to signal the semaphore - RCTSetLogFunction( - ^(RCTLogLevel level, - RCTLogSource source, - __unused NSString *fileName, - __unused NSNumber *lineNumber, - NSString *message) { - if (source == RCTLogSourceJavaScript) { - self->_lastLogLevel = level; - self->_lastLogSource = source; - self->_lastLogMessage = message; - dispatch_semaphore_signal(self->_logSem); - } - }); -} - -- (void)tearDown -{ - [_bridge invalidate]; - _bridge = nil; - - RCTSetLogFunction(RCTDefaultLogFunction); -} - -- (void)testLogging -{ - intptr_t waitRet = 0; - - // First queue the marker and spin until it happens to be logged. - // This is to ensure we skip all of the other messages, that were logged earlier. - NSString *const LogMarker = @"===LOG_MARKER==="; - [_bridge enqueueJSCall:@"LoggingTestModule.logToConsole" args:@[ LogMarker ]]; - - do { - waitRet = dispatch_semaphore_wait(_logSem, dispatch_time(DISPATCH_TIME_NOW, LOGGER_TIMEOUT)); - XCTAssertEqual(waitRet, 0, @"Timed out waiting for log marker"); - } while (waitRet == 0 && ![_lastLogMessage isEqualToString:LogMarker]); - - [_bridge enqueueJSCall:@"LoggingTestModule.logToConsole" args:@[ @"Invoking console.log" ]]; - waitRet = dispatch_semaphore_wait(_logSem, dispatch_time(DISPATCH_TIME_NOW, LOGGER_TIMEOUT)); - XCTAssertEqual(waitRet, 0, @"Timed out waiting for logToConsole"); - - XCTAssertEqual(_lastLogLevel, RCTLogLevelInfo); - XCTAssertEqual(_lastLogSource, RCTLogSourceJavaScript); - XCTAssertEqualObjects(_lastLogMessage, @"Invoking console.log"); - - [_bridge enqueueJSCall:@"LoggingTestModule.warning" args:@[ @"Generating warning" ]]; - waitRet = dispatch_semaphore_wait(_logSem, dispatch_time(DISPATCH_TIME_NOW, LOGGER_TIMEOUT)); - XCTAssertEqual(waitRet, 0, @"Timed out waiting for warning"); - - XCTAssertEqual(_lastLogLevel, RCTLogLevelWarning); - XCTAssertEqual(_lastLogSource, RCTLogSourceJavaScript); - XCTAssertEqualObjects(_lastLogMessage, @"Generating warning"); - - [_bridge enqueueJSCall:@"LoggingTestModule.invariant" args:@[ @"Invariant failed" ]]; - waitRet = dispatch_semaphore_wait(_logSem, dispatch_time(DISPATCH_TIME_NOW, LOGGER_TIMEOUT)); - XCTAssertEqual(waitRet, 0, @"Timed out waiting for invariant"); - - XCTAssertEqual(_lastLogLevel, RCTLogLevelError); - XCTAssertEqual(_lastLogSource, RCTLogSourceJavaScript); - XCTAssertTrue([_lastLogMessage containsString:@"Invariant Violation: Invariant failed"]); - - [_bridge enqueueJSCall:@"LoggingTestModule.logErrorToConsole" args:@[ @"Invoking console.error" ]]; - waitRet = dispatch_semaphore_wait(_logSem, dispatch_time(DISPATCH_TIME_NOW, LOGGER_TIMEOUT)); - XCTAssertEqual(waitRet, 0, @"Timed out waiting for logErrorToConsole"); - - // For local bundles, we may first get a warning about symbolication - if (![_lastLogMessage isEqualToString:@"Invoking console.error"]) { - waitRet = dispatch_semaphore_wait(_logSem, dispatch_time(DISPATCH_TIME_NOW, LOGGER_TIMEOUT)); - XCTAssertEqual(waitRet, 0, @"Timed out waiting for logErrorToConsole #2"); - } - - XCTAssertEqual(_lastLogLevel, RCTLogLevelError); - XCTAssertEqual(_lastLogSource, RCTLogSourceJavaScript); - XCTAssertEqualObjects(_lastLogMessage, @"Invoking console.error"); - - [_bridge enqueueJSCall:@"LoggingTestModule.throwError" args:@[ @"Throwing an error" ]]; - waitRet = dispatch_semaphore_wait(_logSem, dispatch_time(DISPATCH_TIME_NOW, LOGGER_TIMEOUT)); - XCTAssertEqual(waitRet, 0, @"Timed out waiting for throwError"); - - // For local bundles, we may first get a warning about symbolication - if (![_lastLogMessage containsString:@"Error: Throwing an error"]) { - waitRet = dispatch_semaphore_wait(_logSem, dispatch_time(DISPATCH_TIME_NOW, LOGGER_TIMEOUT)); - XCTAssertEqual(waitRet, 0, @"Timed out waiting for throwError #2"); - } - - XCTAssertEqual(_lastLogLevel, RCTLogLevelError); - XCTAssertEqual(_lastLogSource, RCTLogSourceJavaScript); - XCTAssertTrue([_lastLogMessage containsString:@"Error: Throwing an error"]); -} - -@end diff --git a/packages/rn-tester/RNTesterIntegrationTests/RCTUIManagerScenarioTests.m b/packages/rn-tester/RNTesterIntegrationTests/RCTUIManagerScenarioTests.m deleted file mode 100644 index e47c80e56cd39d..00000000000000 --- a/packages/rn-tester/RNTesterIntegrationTests/RCTUIManagerScenarioTests.m +++ /dev/null @@ -1,198 +0,0 @@ -/* - * 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 -#import - -#import -#import - -@interface RCTUIManager (Testing) - -- (void)_manageChildren:(NSNumber *)containerReactTag - moveFromIndices:(NSArray *)moveFromIndices - moveToIndices:(NSArray *)moveToIndices - addChildReactTags:(NSArray *)addChildReactTags - addAtIndices:(NSArray *)addAtIndices - removeAtIndices:(NSArray *)removeAtIndices - registry:(NSMutableDictionary> *)registry; - -@property (nonatomic, readonly) NSMutableDictionary *viewRegistry; - -@end - -@interface RCTUIManagerScenarioTests : XCTestCase - -@property (nonatomic, readwrite, strong) RCTUIManager *uiManager; - -@end - -@implementation RCTUIManagerScenarioTests - -- (void)setUp -{ - [super setUp]; - - _uiManager = [RCTUIManager new]; - - // Register 20 views to use in the tests - for (NSInteger i = 1; i <= 20; i++) { - UIView *registeredView = [UIView new]; - registeredView.reactTag = @(i); - _uiManager.viewRegistry[@(i)] = registeredView; - } -} - -- (void)testManagingChildrenToAddViews -{ - UIView *containerView = _uiManager.viewRegistry[@20]; - NSMutableArray *addedViews = [NSMutableArray array]; - - NSArray *tagsToAdd = @[ @1, @2, @3, @4, @5 ]; - NSArray *addAtIndices = @[ @0, @1, @2, @3, @4 ]; - for (NSNumber *tag in tagsToAdd) { - [addedViews addObject:_uiManager.viewRegistry[tag]]; - } - - // Add views 1-5 to view 20 - [_uiManager _manageChildren:@20 - moveFromIndices:nil - moveToIndices:nil - addChildReactTags:tagsToAdd - addAtIndices:addAtIndices - removeAtIndices:nil - registry:(NSMutableDictionary> *)_uiManager.viewRegistry]; - - [_uiManager.viewRegistry[@20] didUpdateReactSubviews]; - - XCTAssertTrue( - [[containerView reactSubviews] count] == 5, - @"Expect to have 5 react subviews after calling manage children \ - with 5 tags to add, instead have %lu", - (unsigned long)[[containerView reactSubviews] count]); - for (UIView *view in addedViews) { - XCTAssertTrue([view superview] == containerView, @"Expected to have manage children successfully add children"); - [view removeFromSuperview]; - } -} - -- (void)testManagingChildrenToRemoveViews -{ - UIView *containerView = _uiManager.viewRegistry[@20]; - NSMutableArray *removedViews = [NSMutableArray array]; - - NSArray *removeAtIndices = @[ @0, @4, @8, @12, @16 ]; - for (NSNumber *index in removeAtIndices) { - NSNumber *reactTag = @(index.integerValue + 2); - [removedViews addObject:_uiManager.viewRegistry[reactTag]]; - } - for (NSInteger i = 2; i < 20; i++) { - UIView *view = _uiManager.viewRegistry[@(i)]; - [containerView insertReactSubview:view atIndex:containerView.reactSubviews.count]; - } - - // Remove views 1-5 from view 20 - [_uiManager _manageChildren:@20 - moveFromIndices:nil - moveToIndices:nil - addChildReactTags:nil - addAtIndices:nil - removeAtIndices:removeAtIndices - registry:(NSMutableDictionary> *)_uiManager.viewRegistry]; - - [_uiManager.viewRegistry[@20] didUpdateReactSubviews]; - - XCTAssertEqual( - containerView.reactSubviews.count, - (NSUInteger)13, - @"Expect to have 13 react subviews after calling manage children\ - with 5 tags to remove and 18 prior children, instead have %zd", - containerView.reactSubviews.count); - for (UIView *view in removedViews) { - XCTAssertTrue([view superview] == nil, @"Expected to have manage children successfully remove children"); - // After removing views are unregistered - we need to reregister - _uiManager.viewRegistry[view.reactTag] = view; - } - for (NSInteger i = 2; i < 20; i++) { - UIView *view = _uiManager.viewRegistry[@(i)]; - if (![removedViews containsObject:view]) { - XCTAssertTrue( - [view superview] == containerView, - @"Should not have removed view with react tag %ld during delete but did", - (long)i); - [view removeFromSuperview]; - } - } -} - -// We want to start with views 1-10 added at indices 0-9 -// Then we'll remove indices 2, 3, 5 and 8 -// Add views 11 and 12 to indices 0 and 6 -// And move indices 4 and 9 to 1 and 7 -// So in total it goes from: -// [1,2,3,4,5,6,7,8,9,10] -// to -// [11,5,1,2,7,8,12,10] -- (void)testManagingChildrenToAddRemoveAndMove -{ - UIView *containerView = _uiManager.viewRegistry[@20]; - - NSArray *removeAtIndices = @[ @2, @3, @5, @8 ]; - NSArray *addAtIndices = @[ @0, @6 ]; - NSArray *tagsToAdd = @[ @11, @12 ]; - NSArray *moveFromIndices = @[ @4, @9 ]; - NSArray *moveToIndices = @[ @1, @7 ]; - - // We need to keep these in array to keep them around - NSMutableArray *viewsToRemove = [NSMutableArray array]; - for (NSUInteger i = 0; i < removeAtIndices.count; i++) { - NSNumber *reactTagToRemove = @([removeAtIndices[i] integerValue] + 1); - UIView *viewToRemove = _uiManager.viewRegistry[reactTagToRemove]; - [viewsToRemove addObject:viewToRemove]; - } - - for (NSInteger i = 1; i < 11; i++) { - UIView *view = _uiManager.viewRegistry[@(i)]; - [containerView insertReactSubview:view atIndex:containerView.reactSubviews.count]; - } - - [_uiManager _manageChildren:@20 - moveFromIndices:moveFromIndices - moveToIndices:moveToIndices - addChildReactTags:tagsToAdd - addAtIndices:addAtIndices - removeAtIndices:removeAtIndices - registry:(NSMutableDictionary> *)_uiManager.viewRegistry]; - - XCTAssertTrue( - [[containerView reactSubviews] count] == 8, - @"Expect to have 8 react subviews after calling manage children,\ - instead have the following subviews %@", - [containerView reactSubviews]); - - NSArray *expectedReactTags = @[ @11, @5, @1, @2, @7, @8, @12, @10 ]; - for (NSUInteger i = 0; i < containerView.subviews.count; i++) { - XCTAssertEqualObjects( - [[containerView reactSubviews][i] reactTag], - expectedReactTags[i], - @"Expected subview at index %ld to have react tag #%@ but has tag #%@", - (long)i, - expectedReactTags[i], - [[containerView reactSubviews][i] reactTag]); - } - - // Clean up after ourselves - for (NSInteger i = 1; i < 13; i++) { - UIView *view = _uiManager.viewRegistry[@(i)]; - [view removeFromSuperview]; - } - for (UIView *view in viewsToRemove) { - _uiManager.viewRegistry[view.reactTag] = view; - } -} - -@end diff --git a/packages/rn-tester/RNTesterIntegrationTests/RNTesterIntegrationTests.m b/packages/rn-tester/RNTesterIntegrationTests/RNTesterIntegrationTests.m deleted file mode 100644 index f2ae63646751dd..00000000000000 --- a/packages/rn-tester/RNTesterIntegrationTests/RNTesterIntegrationTests.m +++ /dev/null @@ -1,77 +0,0 @@ -/* - * 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 -#import - -#import - -#define RCT_TEST(name) \ - -(void)test##name \ - { \ - [_runner runTest:_cmd module:@ #name]; \ - } - -#define RCT_TEST_ONLY_WITH_PACKAGER(name) \ - -(void)test##name \ - { \ - if (getenv("CI_USE_PACKAGER")) { \ - [_runner runTest:_cmd module:@ #name]; \ - } \ - } - -@interface RNTesterIntegrationTests : XCTestCase - -@end - -@implementation RNTesterIntegrationTests { - RCTTestRunner *_runner; -} - -- (void)setUp -{ - _runner = RCTInitRunnerForApp(@"IntegrationTests/IntegrationTestsApp", nil, nil); - _runner.recordMode = NO; -} - -#pragma mark - Test harness - -- (void)testTheTester_waitOneFrame -{ - [_runner runTest:_cmd - module:@"IntegrationTestHarnessTest" - initialProps:@{@"waitOneFrame" : @YES} - configurationBlock:nil]; -} - -// Disabled -//- (void)testTheTester_ExpectError -//{ -// [_runner runTest:_cmd -// module:@"IntegrationTestHarnessTest" -// initialProps:@{@"shouldThrow": @YES} -// configurationBlock:nil -// expectErrorRegex:@"because shouldThrow"]; -//} - -#pragma mark - JS tests - -// This list should be kept in sync with IntegrationTestsApp.js -RCT_TEST(IntegrationTestHarnessTest) -// RCT_TEST(TimersTest) // Disabled due to issue introduced in 61346d3 -RCT_TEST(AppEventsTest) -// RCT_TEST(ImageCachePolicyTest) // This test never passed. -RCT_TEST(ImageSnapshotTest) -// RCT_TEST(LayoutEventsTest) // Disabled due to flakiness: #8686784 -RCT_TEST(SimpleSnapshotTest) -RCT_TEST(SyncMethodTest) -RCT_TEST(PromiseTest) -RCT_TEST_ONLY_WITH_PACKAGER(WebSocketTest) // Requires a WebSocket test server, see scripts/objc-test.sh -RCT_TEST(AccessibilityManagerTest) -RCT_TEST(GlobalEvalWithSourceUrlTest) - -@end diff --git a/packages/rn-tester/RNTesterIntegrationTests/RNTesterTestModule.m b/packages/rn-tester/RNTesterIntegrationTests/RNTesterTestModule.m deleted file mode 100644 index cc444d4d181575..00000000000000 --- a/packages/rn-tester/RNTesterIntegrationTests/RNTesterTestModule.m +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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 - -#import - -@interface RNTesterTestModule : NSObject - -@end - -@implementation RNTesterTestModule - -RCT_EXPORT_MODULE(RNTesterTestModule) - -RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(echoString : (NSString *)input) -{ - return input; -} - -RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(methodThatReturnsNil) -{ - return nil; -} - -RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(methodThatCallsCallbackWithString - : (NSString *)input callback - : (RCTResponseSenderBlock)callback) -{ - callback(@[ input ]); - return nil; -} - -@end diff --git a/packages/rn-tester/RNTesterIntegrationTests/ReferenceImages/IntegrationTests-IntegrationTestsApp/testImageSnapshotTest_1@2x.png b/packages/rn-tester/RNTesterIntegrationTests/ReferenceImages/IntegrationTests-IntegrationTestsApp/testImageSnapshotTest_1@2x.png deleted file mode 100644 index adf8f217a5dd75..00000000000000 Binary files a/packages/rn-tester/RNTesterIntegrationTests/ReferenceImages/IntegrationTests-IntegrationTestsApp/testImageSnapshotTest_1@2x.png and /dev/null differ diff --git a/packages/rn-tester/RNTesterIntegrationTests/ReferenceImages/IntegrationTests-IntegrationTestsApp/testImageSnapshotTest_1@3x.png b/packages/rn-tester/RNTesterIntegrationTests/ReferenceImages/IntegrationTests-IntegrationTestsApp/testImageSnapshotTest_1@3x.png deleted file mode 100644 index c12d1644e280a6..00000000000000 Binary files a/packages/rn-tester/RNTesterIntegrationTests/ReferenceImages/IntegrationTests-IntegrationTestsApp/testImageSnapshotTest_1@3x.png and /dev/null differ diff --git a/packages/rn-tester/RNTesterIntegrationTests/ReferenceImages/IntegrationTests-IntegrationTestsApp/testSimpleSnapshotTest_1@2x.png b/packages/rn-tester/RNTesterIntegrationTests/ReferenceImages/IntegrationTests-IntegrationTestsApp/testSimpleSnapshotTest_1@2x.png deleted file mode 100644 index fd91abf4238eee..00000000000000 Binary files a/packages/rn-tester/RNTesterIntegrationTests/ReferenceImages/IntegrationTests-IntegrationTestsApp/testSimpleSnapshotTest_1@2x.png and /dev/null differ diff --git a/packages/rn-tester/RNTesterIntegrationTests/ReferenceImages/IntegrationTests-IntegrationTestsApp/testSimpleSnapshotTest_1@3x.png b/packages/rn-tester/RNTesterIntegrationTests/ReferenceImages/IntegrationTests-IntegrationTestsApp/testSimpleSnapshotTest_1@3x.png deleted file mode 100644 index a7f45cd033c18f..00000000000000 Binary files a/packages/rn-tester/RNTesterIntegrationTests/ReferenceImages/IntegrationTests-IntegrationTestsApp/testSimpleSnapshotTest_1@3x.png and /dev/null differ diff --git a/packages/rn-tester/RNTesterIntegrationTests/blue_square.png b/packages/rn-tester/RNTesterIntegrationTests/blue_square.png deleted file mode 100644 index 4974e084c63652..00000000000000 Binary files a/packages/rn-tester/RNTesterIntegrationTests/blue_square.png and /dev/null differ diff --git a/packages/rn-tester/RNTesterIntegrationTests/red_square.png b/packages/rn-tester/RNTesterIntegrationTests/red_square.png deleted file mode 100644 index 0977a3e8cf337e..00000000000000 Binary files a/packages/rn-tester/RNTesterIntegrationTests/red_square.png and /dev/null differ diff --git a/packages/rn-tester/RNTesterUnitTests/Info.plist b/packages/rn-tester/RNTesterUnitTests/Info.plist deleted file mode 100644 index 6c40a6cd0c4af2..00000000000000 --- a/packages/rn-tester/RNTesterUnitTests/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - BNDL - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - - diff --git a/packages/rn-tester/RNTesterUnitTests/RCTAllocationTests.m b/packages/rn-tester/RNTesterUnitTests/RCTAllocationTests.m deleted file mode 100644 index ed1f3a7e5da1ea..00000000000000 --- a/packages/rn-tester/RNTesterUnitTests/RCTAllocationTests.m +++ /dev/null @@ -1,214 +0,0 @@ -/* - * 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 -#import - -#import -#import -#import -#import -#import - -@interface AllocationTestModule : NSObject - -@property (atomic, assign, getter=isValid) BOOL valid; - -@end - -@implementation AllocationTestModule - -RCT_EXPORT_MODULE(); - -- (instancetype)init -{ - if ((self = [super init])) { - self.valid = YES; - } - return self; -} - -- (void)invalidate -{ - self.valid = NO; -} - -RCT_EXPORT_METHOD(test - : (__unused NSString *)a - : (__unused NSNumber *)b - : (__unused RCTResponseSenderBlock)c - : (__unused RCTResponseErrorBlock)d) -{ -} - -@end - -@interface RCTAllocationTests : XCTestCase -@end - -@implementation RCTAllocationTests { - NSURL *_bundleURL; -} - -- (void)setUp -{ - [super setUp]; - - NSString *bundleContents = - @"var __fbBatchedBridge = {" - " callFunctionReturnFlushedQueue: function() { return null; }," - " invokeCallbackAndReturnFlushedQueue: function() { return null; }," - " flushedQueue: function() { return null; }," - "};"; - - NSURL *tempDir = [NSURL fileURLWithPath:NSTemporaryDirectory() isDirectory:YES]; - [[NSFileManager defaultManager] createDirectoryAtURL:tempDir - withIntermediateDirectories:YES - attributes:nil - error:NULL]; - NSString *guid = [[NSProcessInfo processInfo] globallyUniqueString]; - NSString *fileName = [NSString stringWithFormat:@"rctallocationtests-bundle-%@.js", guid]; - - _bundleURL = [tempDir URLByAppendingPathComponent:fileName]; - NSError *saveError; - if (![bundleContents writeToURL:_bundleURL atomically:YES encoding:NSUTF8StringEncoding error:&saveError]) { - XCTFail(@"Failed to save test bundle to %@, error: %@", _bundleURL, saveError); - }; -} - -- (void)tearDown -{ - [super tearDown]; - - [[NSFileManager defaultManager] removeItemAtURL:_bundleURL error:NULL]; -} - -- (void)testBridgeIsDeallocated -{ - __weak RCTBridge *weakBridge; - @autoreleasepool { - RCTRootView *view = [[RCTRootView alloc] initWithBundleURL:_bundleURL - moduleName:@"" - initialProperties:nil - launchOptions:nil]; - weakBridge = view.bridge; - XCTAssertNotNil(weakBridge, @"RCTBridge should have been created"); - (void)view; - } - - XCTAssertNil(weakBridge, @"RCTBridge should have been deallocated"); -} - -- (void)testModulesAreInvalidated -{ - AllocationTestModule *module = [AllocationTestModule new]; - @autoreleasepool { - RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:_bundleURL - moduleProvider:^{ - return @[ module ]; - } - launchOptions:nil]; - XCTAssertTrue(module.isValid, @"AllocationTestModule should be valid"); - (void)bridge; - } - - RCT_RUN_RUNLOOP_WHILE(module.isValid) - XCTAssertFalse(module.isValid, @"AllocationTestModule should have been invalidated by the bridge"); -} - -- (void)testModulesAreDeallocated -{ - __weak AllocationTestModule *weakModule; - @autoreleasepool { - AllocationTestModule *module = [AllocationTestModule new]; - RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:_bundleURL - moduleProvider:^{ - return @[ module ]; - } - launchOptions:nil]; - XCTAssertNotNil(module, @"AllocationTestModule should have been created"); - weakModule = module; - (void)bridge; - } - - RCT_RUN_RUNLOOP_WHILE(weakModule) - XCTAssertNil(weakModule, @"AllocationTestModule should have been deallocated"); -} - -- (void)testModuleMethodsAreDeallocated -{ - static RCTMethodInfo methodInfo = { - .objcName = "test:(NSString *)a :(nonnull NSNumber *)b :(RCTResponseSenderBlock)c :(RCTResponseErrorBlock)d", - .jsName = "", - .isSync = false}; - - __weak RCTModuleMethod *weakMethod; - @autoreleasepool { - __autoreleasing RCTModuleMethod *method = - [[RCTModuleMethod alloc] initWithExportedMethod:&methodInfo moduleClass:[AllocationTestModule class]]; - XCTAssertNotNil(method, @"RCTModuleMethod should have been created"); - weakMethod = method; - } - - RCT_RUN_RUNLOOP_WHILE(weakMethod) - XCTAssertNil(weakMethod, @"RCTModuleMethod should have been deallocated"); -} - -- (void)testContentViewIsInvalidated -{ - RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:_bundleURL moduleProvider:nil launchOptions:nil]; - __weak UIView *rootContentView; - @autoreleasepool { - RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge moduleName:@"" initialProperties:nil]; - RCT_RUN_RUNLOOP_WHILE(!(rootContentView = [rootView valueForKey:@"contentView"])) - XCTAssertTrue(rootContentView.userInteractionEnabled, @"RCTContentView should be valid"); - (void)rootView; - } - -#if !TARGET_OS_TV // userInteractionEnabled is true for Apple TV views - XCTAssertFalse(rootContentView.userInteractionEnabled, @"RCTContentView should have been invalidated"); -#endif -} - -/** - * T42930872: - * - * Both bridge invalidation and bridge setUp occur execute concurrently. - * Therefore, it's not safe for us to create a bridge, and immediately reload on - * it. It's also unsafe to just reload the bridge, because that calls invalidate - * and then setUp. Because of these race conditions, this test may randomly - * crash. Hence, we should disable this test until we either fix the bridge - * or delete it. - */ -- (void)disabled_testUnderlyingBridgeIsDeallocated -{ - RCTBridge *bridge; - __weak id batchedBridge; - @autoreleasepool { - bridge = [[RCTBridge alloc] initWithBundleURL:_bundleURL moduleProvider:nil launchOptions:nil]; - batchedBridge = bridge.batchedBridge; - XCTAssertTrue([batchedBridge isValid], @"RCTBridge impl should be valid"); - [bridge reload]; - } - - RCT_RUN_RUNLOOP_WHILE(batchedBridge != nil) - - XCTAssertNotNil(bridge, @"RCTBridge should not have been deallocated"); - XCTAssertNil(batchedBridge, @"RCTBridge impl should have been deallocated"); - - // Wait to complete the test until the new bridge impl is also deallocated - @autoreleasepool { - batchedBridge = bridge.batchedBridge; - [bridge invalidate]; - bridge = nil; - } - - RCT_RUN_RUNLOOP_WHILE(batchedBridge != nil); - XCTAssertNil(batchedBridge); -} - -@end diff --git a/packages/rn-tester/RNTesterUnitTests/RCTAnimationUtilsTests.m b/packages/rn-tester/RNTesterUnitTests/RCTAnimationUtilsTests.m deleted file mode 100644 index 5926ffd38278f1..00000000000000 --- a/packages/rn-tester/RNTesterUnitTests/RCTAnimationUtilsTests.m +++ /dev/null @@ -1,128 +0,0 @@ -/* - * 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 - -#import -#import -#import - -@interface RCTAnimationUtilsTests : XCTestCase - -@end - -static CGFloat RCTSimpleInterpolation(CGFloat value, NSArray *inputRange, NSArray *outputRange) -{ - return RCTInterpolateValueInRange(value, inputRange, outputRange, EXTRAPOLATE_TYPE_EXTEND, EXTRAPOLATE_TYPE_EXTEND); -} - -@implementation RCTAnimationUtilsTests - -// RCTInterpolateValueInRange - -- (void)testSimpleOneToOneMapping -{ - NSArray *input = @[ @0, @1 ]; - NSArray *output = @[ @0, @1 ]; - XCTAssertEqual(RCTSimpleInterpolation(0, input, output), 0); - XCTAssertEqual(RCTSimpleInterpolation(0.5, input, output), 0.5); - XCTAssertEqual(RCTSimpleInterpolation(0.8, input, output), 0.8); - XCTAssertEqual(RCTSimpleInterpolation(1, input, output), 1); -} - -- (void)testWiderOutputRange -{ - NSArray *input = @[ @0, @1 ]; - NSArray *output = @[ @100, @200 ]; - XCTAssertEqual(RCTSimpleInterpolation(0, input, output), 100); - XCTAssertEqual(RCTSimpleInterpolation(0.5, input, output), 150); - XCTAssertEqual(RCTSimpleInterpolation(0.8, input, output), 180); - XCTAssertEqual(RCTSimpleInterpolation(1, input, output), 200); -} - -- (void)testWiderInputRange -{ - NSArray *input = @[ @2000, @3000 ]; - NSArray *output = @[ @1, @2 ]; - XCTAssertEqual(RCTSimpleInterpolation(2000, input, output), 1); - XCTAssertEqual(RCTSimpleInterpolation(2250, input, output), 1.25); - XCTAssertEqual(RCTSimpleInterpolation(2800, input, output), 1.8); - XCTAssertEqual(RCTSimpleInterpolation(3000, input, output), 2); -} - -- (void)testManySegments -{ - NSArray *input = @[ @-1, @1, @5 ]; - NSArray *output = @[ @0, @10, @20 ]; - XCTAssertEqual(RCTSimpleInterpolation(-1, input, output), 0); - XCTAssertEqual(RCTSimpleInterpolation(0, input, output), 5); - XCTAssertEqual(RCTSimpleInterpolation(1, input, output), 10); - XCTAssertEqual(RCTSimpleInterpolation(2, input, output), 12.5); - XCTAssertEqual(RCTSimpleInterpolation(5, input, output), 20); -} - -- (void)testExtendExtrapolate -{ - NSArray *input = @[ @10, @20 ]; - NSArray *output = @[ @0, @1 ]; - XCTAssertEqual(RCTSimpleInterpolation(30, input, output), 2); - XCTAssertEqual(RCTSimpleInterpolation(5, input, output), -0.5); -} - -- (void)testClampExtrapolate -{ - NSArray *input = @[ @10, @20 ]; - NSArray *output = @[ @0, @1 ]; - CGFloat value; - value = RCTInterpolateValueInRange(30, input, output, EXTRAPOLATE_TYPE_CLAMP, EXTRAPOLATE_TYPE_CLAMP); - XCTAssertEqual(value, 1); - value = RCTInterpolateValueInRange(5, input, output, EXTRAPOLATE_TYPE_CLAMP, EXTRAPOLATE_TYPE_CLAMP); - XCTAssertEqual(value, 0); -} - -- (void)testIdentityExtrapolate -{ - NSArray *input = @[ @10, @20 ]; - NSArray *output = @[ @0, @1 ]; - CGFloat value; - value = RCTInterpolateValueInRange(30, input, output, EXTRAPOLATE_TYPE_IDENTITY, EXTRAPOLATE_TYPE_IDENTITY); - XCTAssertEqual(value, 30); - value = RCTInterpolateValueInRange(5, input, output, EXTRAPOLATE_TYPE_IDENTITY, EXTRAPOLATE_TYPE_IDENTITY); - XCTAssertEqual(value, 5); -} - -- (void)testColorInterpolation -{ - NSArray *input = @[ @0, @1 ]; - NSArray *output = @[ [UIColor redColor], [UIColor blueColor] ]; - uint32_t value; - value = RCTInterpolateColorInRange(0, input, output); - XCTAssertEqualObjects([RCTConvert UIColor:@(value)], [UIColor redColor]); - value = RCTInterpolateColorInRange(0.5, input, output); - XCTAssertEqualObjects( - [RCTConvert UIColor:@(value)], [UIColor colorWithRed:128. / 255 green:0 blue:128. / 255 alpha:1]); - value = RCTInterpolateColorInRange(1, input, output); - XCTAssertEqualObjects([RCTConvert UIColor:@(value)], [UIColor blueColor]); -} - -- (void)testStringInterpolation -{ - NSString *pattern = @"M20,20L20,80L80,80L80,20Z"; - NSArray *input = @[ @0, @1 ]; - NSArray *> *output = @[ - @[ @20, @20, @20, @80, @80, @80, @80, @20 ], - @[ @40, @40, @33, @60, @60, @60, @65, @40 ], - ]; - - NSString *value; - value = RCTInterpolateString(pattern, 0, input, output, EXTRAPOLATE_TYPE_IDENTITY, EXTRAPOLATE_TYPE_IDENTITY); - XCTAssertEqualObjects(value, @"M20,20L20,80L80,80L80,20Z"); - value = RCTInterpolateString(pattern, 0.5, input, output, EXTRAPOLATE_TYPE_IDENTITY, EXTRAPOLATE_TYPE_IDENTITY); - XCTAssertEqualObjects(value, @"M30,30L26.5,70L70,70L72.5,30Z"); -} - -@end diff --git a/packages/rn-tester/RNTesterUnitTests/RCTBlobManagerTests.m b/packages/rn-tester/RNTesterUnitTests/RCTBlobManagerTests.m deleted file mode 100644 index 2bbf23e657dda3..00000000000000 --- a/packages/rn-tester/RNTesterUnitTests/RCTBlobManagerTests.m +++ /dev/null @@ -1,101 +0,0 @@ -/* - * 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 - -#import - -@interface RCTBlobManagerTests : XCTestCase - -@end - -@implementation RCTBlobManagerTests { - RCTBlobManager *_module; - NSMutableData *_data; - NSString *_blobId; -} - -- (void)setUp -{ - [super setUp]; - - _module = [RCTBlobManager new]; - [_module setValue:nil forKey:@"bridge"]; - [_module initialize]; - NSInteger size = 120; - _data = [NSMutableData dataWithCapacity:size]; - for (NSInteger i = 0; i < size / 4; i++) { - uint32_t randomBits = arc4random(); - [_data appendBytes:(void *)&randomBits length:4]; - } - _blobId = [NSUUID UUID].UUIDString; - [_module store:_data withId:_blobId]; -} - -- (void)testResolve -{ - XCTAssertTrue([_data isEqualToData:[_module resolve:_blobId offset:0 size:_data.length]]); - NSData *rangeData = [_data subdataWithRange:NSMakeRange(30, _data.length - 30)]; - XCTAssertTrue([rangeData isEqualToData:[_module resolve:_blobId offset:30 size:_data.length - 30]]); -} - -- (void)testResolveMap -{ - NSDictionary *map = @{ - @"blobId" : _blobId, - @"size" : @(_data.length), - @"offset" : @0, - }; - XCTAssertTrue([_data isEqualToData:[_module resolve:map]]); -} - -- (void)testResolveURL -{ - NSURLComponents *components = [NSURLComponents new]; - [components setPath:_blobId]; - [components setQuery:[NSString stringWithFormat:@"offset=0&size=%lu", (unsigned long)_data.length]]; - XCTAssertTrue([_data isEqualToData:[_module resolveURL:[components URL]]]); -} - -- (void)testRemove -{ - XCTAssertNotNil([_module resolve:_blobId offset:0 size:_data.length]); - [_module remove:_blobId]; - XCTAssertNil([_module resolve:_blobId offset:0 size:_data.length]); -} - -- (void)testCreateFromParts -{ - NSDictionary *blobData = @{ - @"blobId" : _blobId, - @"offset" : @0, - @"size" : @(_data.length), - }; - NSDictionary *blob = @{ - @"data" : blobData, - @"type" : @"blob", - }; - NSString *stringData = @"i \u2665 dogs"; - NSDictionary *string = @{ - @"data" : stringData, - @"type" : @"string", - }; - NSString *resultId = [NSUUID UUID].UUIDString; - NSArray *parts = @[ blob, string ]; - - [_module createFromParts:parts withId:resultId]; - - NSMutableData *expectedData = [NSMutableData new]; - [expectedData appendData:_data]; - [expectedData appendData:[stringData dataUsingEncoding:NSUTF8StringEncoding]]; - - NSData *result = [_module resolve:resultId offset:0 size:expectedData.length]; - - XCTAssertTrue([expectedData isEqualToData:result]); -} - -@end diff --git a/packages/rn-tester/RNTesterUnitTests/RCTBundleURLProviderTests.m b/packages/rn-tester/RNTesterUnitTests/RCTBundleURLProviderTests.m deleted file mode 100644 index 6d1fb5e1cf47e0..00000000000000 --- a/packages/rn-tester/RNTesterUnitTests/RCTBundleURLProviderTests.m +++ /dev/null @@ -1,112 +0,0 @@ -/* - * 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 - -#import -#import -#import - -#import "OCMock/OCMock.h" - -static NSString *const testFile = @"test.jsbundle"; -static NSString *const mainBundle = @"main.jsbundle"; - -static NSURL *mainBundleURL(void) -{ - return [[[NSBundle mainBundle] bundleURL] URLByAppendingPathComponent:mainBundle]; -} - -static NSURL *localhostBundleURL(void) -{ - return [NSURL - URLWithString: - [NSString - stringWithFormat: - @"http://localhost:8081/%@.bundle?platform=%@&dev=true&lazy=true&minify=false&inlineSourceMap=false&modulesOnly=false&runModule=true&app=com.apple.dt.xctest.tool", - testFile, - RCTPlatformName]]; -} - -static NSURL *ipBundleURL(void) -{ - return [NSURL - URLWithString: - [NSString - stringWithFormat: - @"http://192.168.1.1:8081/%@.bundle?platform=%@&dev=true&lazy=true&minify=false&inlineSourceMap=false&modulesOnly=false&runModule=true&app=com.apple.dt.xctest.tool", - testFile, - RCTPlatformName]]; -} - -@implementation NSBundle (RCTBundleURLProviderTests) - -- (NSURL *)RCT_URLForResource:(NSString *)name withExtension:(NSString *)ext -{ - // Ensure that test files is always reported as existing - if ([[name stringByAppendingFormat:@".%@", ext] isEqualToString:mainBundle]) { - return [[self bundleURL] URLByAppendingPathComponent:mainBundle]; - } - return [self RCT_URLForResource:name withExtension:ext]; -} - -@end - -@interface RCTBundleURLProviderTests : XCTestCase -@end - -@implementation RCTBundleURLProviderTests - -- (void)setUp -{ - [super setUp]; - - RCTSwapInstanceMethods( - [NSBundle class], @selector(URLForResource:withExtension:), @selector(RCT_URLForResource:withExtension:)); -} - -- (void)tearDown -{ - RCTSwapInstanceMethods( - [NSBundle class], @selector(URLForResource:withExtension:), @selector(RCT_URLForResource:withExtension:)); - - [super tearDown]; -} - -- (void)testBundleURL -{ - RCTBundleURLProvider *settings = [RCTBundleURLProvider sharedSettings]; - settings.jsLocation = nil; - NSURL *URL = [settings jsBundleURLForBundleRoot:testFile]; - if (!getenv("CI_USE_PACKAGER")) { - XCTAssertEqualObjects(URL, mainBundleURL()); - } else { - XCTAssertEqualObjects(URL, localhostBundleURL()); - } -} - -- (void)testLocalhostURL -{ - id classMock = OCMClassMock([RCTBundleURLProvider class]); - [[[classMock stub] andReturnValue:@YES] isPackagerRunning:[OCMArg any] scheme:[OCMArg any]]; - RCTBundleURLProvider *settings = [RCTBundleURLProvider sharedSettings]; - settings.jsLocation = @"localhost"; - NSURL *URL = [settings jsBundleURLForBundleRoot:testFile]; - XCTAssertEqualObjects(URL, localhostBundleURL()); -} - -- (void)testIPURL -{ - id classMock = OCMClassMock([RCTBundleURLProvider class]); - [[[classMock stub] andReturnValue:@YES] isPackagerRunning:[OCMArg any] scheme:[OCMArg any]]; - RCTBundleURLProvider *settings = [RCTBundleURLProvider sharedSettings]; - settings.jsLocation = @"192.168.1.1"; - NSURL *URL = [settings jsBundleURLForBundleRoot:testFile]; - XCTAssertEqualObjects(URL, ipBundleURL()); -} - -@end diff --git a/packages/rn-tester/RNTesterUnitTests/RCTComponentPropsTests.m b/packages/rn-tester/RNTesterUnitTests/RCTComponentPropsTests.m deleted file mode 100644 index c943d9d0a7700a..00000000000000 --- a/packages/rn-tester/RNTesterUnitTests/RCTComponentPropsTests.m +++ /dev/null @@ -1,203 +0,0 @@ -/* - * 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 - -#import -#import -#import -#import -#import -#import - -@interface RCTUIManager () - -- (void)createView:(NSNumber *)reactTag - viewName:(NSString *)viewName - rootTag:(NSNumber *)rootTag - props:(NSDictionary *)props; - -- (void)updateView:(nonnull NSNumber *)reactTag viewName:(NSString *)viewName props:(NSDictionary *)props; - -@property (nonatomic, copy, readonly) NSMutableDictionary *shadowViewRegistry; - -@end - -@interface RCTPropsTestView : UIView - -@property (nonatomic, assign) NSInteger integerProp; -@property (nonatomic, strong) id objectProp; -@property (nonatomic, assign) CGPoint structProp; -@property (nonatomic, copy) NSString *customProp; - -@end - -@implementation RCTPropsTestView -@end - -@interface RCTPropsTestViewManager : RCTViewManager -@end - -@implementation RCTPropsTestViewManager - -RCT_EXPORT_MODULE() - -- (UIView *)view -{ - RCTPropsTestView *view = [RCTPropsTestView new]; - view.integerProp = 57; - view.objectProp = @9; - view.structProp = CGPointMake(5, 6); - view.customProp = @"Hello"; - return view; -} - -RCT_EXPORT_VIEW_PROPERTY(integerProp, NSInteger) -RCT_EXPORT_VIEW_PROPERTY(objectProp, NSNumber) -RCT_EXPORT_VIEW_PROPERTY(structProp, CGPoint) -RCT_CUSTOM_VIEW_PROPERTY(customProp, NSString, RCTPropsTestView) -{ - view.customProp = json ? [RCTConvert NSString:json] : defaultView.customProp; -} - -@end - -@interface RCTComponentPropsTests : XCTestCase - -@end - -@implementation RCTComponentPropsTests { - RCTBridge *_bridge; - NSNumber *_rootViewReactTag; -} - -- (void)setUp -{ - [super setUp]; - - NSBundle *bundle = [NSBundle bundleForClass:[self class]]; - _bridge = [[RCTBridge alloc] initWithBundleURL:[bundle URLForResource:@"RNTesterUnitTestsBundle" withExtension:@"js"] - moduleProvider:nil - launchOptions:nil]; - - _rootViewReactTag = @1; - RCTUIManager *uiManager = _bridge.uiManager; - - dispatch_async(uiManager.methodQueue, ^{ - RCTRootShadowView *rootShadowView = [RCTRootShadowView new]; - rootShadowView.reactTag = self->_rootViewReactTag; - uiManager.shadowViewRegistry[rootShadowView.reactTag] = rootShadowView; - }); - - RCT_RUN_RUNLOOP_WHILE(_bridge.isLoading); -} - -- (void)testSetProps -{ - __block RCTPropsTestView *view; - RCTUIManager *uiManager = _bridge.uiManager; - NSDictionary *props = - @{@"integerProp" : @58, @"objectProp" : @10, @"structProp" : @{@"x" : @7, @"y" : @8}, @"customProp" : @"Goodbye"}; - - dispatch_async(uiManager.methodQueue, ^{ - [uiManager createView:@2 viewName:@"RCTPropsTestView" rootTag:self->_rootViewReactTag props:props]; - [uiManager addUIBlock:^(__unused RCTUIManager *_uiManager, NSDictionary *viewRegistry) { - view = (RCTPropsTestView *)viewRegistry[@2]; - XCTAssertEqual(view.integerProp, 58); - XCTAssertEqualObjects(view.objectProp, @10); - XCTAssertTrue(CGPointEqualToPoint(view.structProp, CGPointMake(7, 8))); - XCTAssertEqualObjects(view.customProp, @"Goodbye"); - }]; - [uiManager setNeedsLayout]; - }); - - RCT_RUN_RUNLOOP_WHILE(view == nil); -} - -- (void)testNeedsOffscreenAlphaCompositing -{ - __block RCTPropsTestView *view; - RCTUIManager *uiManager = _bridge.uiManager; - - XCTestExpectation *initialExpectation = [self expectationWithDescription:@"initial expectation"]; - XCTestExpectation *updateExpectation = [self expectationWithDescription:@"second expectation"]; - - dispatch_async(uiManager.methodQueue, ^{ - [uiManager createView:@2 viewName:@"RCTPropsTestView" rootTag:self->_rootViewReactTag props:@{}]; - [uiManager addUIBlock:^(__unused RCTUIManager *_uiManager, NSDictionary *viewRegistry) { - view = (RCTPropsTestView *)viewRegistry[@2]; - XCTAssertEqual(view.layer.allowsGroupOpacity, TRUE); - [initialExpectation fulfill]; - }]; - [uiManager updateView:@2 viewName:@"RCTPropsTestView" props:@{@"needsOffscreenAlphaCompositing" : @NO}]; - [uiManager addUIBlock:^(__unused RCTUIManager *_uiManager, NSDictionary *viewRegistry) { - view = (RCTPropsTestView *)viewRegistry[@2]; - XCTAssertEqual(view.layer.allowsGroupOpacity, FALSE); - [updateExpectation fulfill]; - }]; - [uiManager setNeedsLayout]; - }); - - [self waitForExpectations:@[ initialExpectation, updateExpectation ] timeout:0.1]; -} - -- (void)testResetProps -{ - __block RCTPropsTestView *view; - RCTUIManager *uiManager = _bridge.uiManager; - NSDictionary *props = - @{@"integerProp" : @58, @"objectProp" : @10, @"structProp" : @{@"x" : @7, @"y" : @8}, @"customProp" : @"Goodbye"}; - - NSDictionary *resetProps = @{ - @"integerProp" : [NSNull null], - @"objectProp" : [NSNull null], - @"structProp" : [NSNull null], - @"customProp" : [NSNull null] - }; - - dispatch_async(uiManager.methodQueue, ^{ - [uiManager createView:@2 viewName:@"RCTPropsTestView" rootTag:self->_rootViewReactTag props:props]; - [uiManager updateView:@2 viewName:@"RCTPropsTestView" props:resetProps]; - [uiManager addUIBlock:^(__unused RCTUIManager *_uiManager, NSDictionary *viewRegistry) { - view = (RCTPropsTestView *)viewRegistry[@2]; - XCTAssertEqual(view.integerProp, 57); - XCTAssertEqualObjects(view.objectProp, @9); - XCTAssertTrue(CGPointEqualToPoint(view.structProp, CGPointMake(5, 6))); - XCTAssertEqualObjects(view.customProp, @"Hello"); - }]; - [uiManager setNeedsLayout]; - }); - - RCT_RUN_RUNLOOP_WHILE(view == nil); -} - -- (void)testResetBackgroundColor -{ - __block RCTView *view; - RCTUIManager *uiManager = _bridge.uiManager; - NSDictionary *props = @{@"backgroundColor" : @0xffffffff}; - NSDictionary *resetProps = @{@"backgroundColor" : [NSNull null]}; - - dispatch_async(uiManager.methodQueue, ^{ - [uiManager createView:@2 viewName:@"RCTView" rootTag:self->_rootViewReactTag props:props]; - [uiManager addUIBlock:^(__unused RCTUIManager *_uiManager, NSDictionary *viewRegistry) { - view = (RCTView *)viewRegistry[@2]; - XCTAssertEqualObjects(view.backgroundColor, [RCTConvert UIColor:@0xffffffff]); - }]; - [uiManager updateView:@2 viewName:@"RCTView" props:resetProps]; - [uiManager - addUIBlock:^(__unused RCTUIManager *_uiManager, __unused NSDictionary *viewRegistry) { - view = (RCTView *)viewRegistry[@2]; - XCTAssertNil(view.backgroundColor); - }]; - [uiManager setNeedsLayout]; - }); - - RCT_RUN_RUNLOOP_WHILE(view == nil); -} - -@end diff --git a/packages/rn-tester/RNTesterUnitTests/RCTConvert_NSURLTests.m b/packages/rn-tester/RNTesterUnitTests/RCTConvert_NSURLTests.m deleted file mode 100644 index 7d3dadde38fbc8..00000000000000 --- a/packages/rn-tester/RNTesterUnitTests/RCTConvert_NSURLTests.m +++ /dev/null @@ -1,80 +0,0 @@ -/* - * 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 - -#import -#import - -@interface RCTConvert_NSURLTests : XCTestCase - -@end - -@implementation RCTConvert_NSURLTests - -#define TEST_URL(name, _input, _expectedURL) \ - -(void)test_##name \ - { \ - NSURL *result = [RCTConvert NSURL:_input]; \ - XCTAssertEqualObjects(result.absoluteString, _expectedURL); \ - } - -#define TEST_PATH(name, _input, _expectedPath) \ - -(void)test_##name \ - { \ - NSURL *result = [RCTConvert NSURL:_input]; \ - XCTAssertEqualObjects(result.path, _expectedPath); \ - } - -#define TEST_BUNDLE_PATH(name, _input, _expectedPath) \ - TEST_PATH(name, _input, [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:_expectedPath]) - -// Basic tests -TEST_URL(basic, @"http://example.com", @"http://example.com") -TEST_URL(null, (id)kCFNull, nil) - -// Resource files -TEST_PATH(fileURL, @"file:///blah/hello.jsbundle", @"/blah/hello.jsbundle") -TEST_BUNDLE_PATH(filePath, @"blah/hello.jsbundle", @"blah/hello.jsbundle") -TEST_BUNDLE_PATH(filePathWithSpaces, @"blah blah/hello.jsbundle", @"blah blah/hello.jsbundle") -TEST_BUNDLE_PATH(filePathWithEncodedSpaces, @"blah%20blah/hello.jsbundle", @"blah blah/hello.jsbundle") -TEST_BUNDLE_PATH(imageAt2XPath, @"images/foo@2x.jpg", @"images/foo@2x.jpg") -TEST_BUNDLE_PATH(imageFile, @"foo.jpg", @"foo.jpg") - -TEST_BUNDLE_PATH(imageFileWithSemicolon, @"folder/foo:bar-baz.jpg", @"folder/foo:bar-baz.jpg") -TEST_URL(filePathWithSemicolon, @"/folder/foo:bar-baz.jpg", @"file:///folder/foo:bar-baz.jpg") - -// User documents -TEST_PATH( - documentsFolder, - @"~/Documents", - [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]) - -// Remote files -TEST_URL(fullURL, @"http://example.com/blah/hello.jsbundle", @"http://example.com/blah/hello.jsbundle") -TEST_URL(urlWithSpaces, @"http://example.com/blah blah/foo", @"http://example.com/blah%20blah/foo") -TEST_URL(urlWithEncodedSpaces, @"http://example.com/blah%20blah/foo", @"http://example.com/blah%20blah/foo") -TEST_URL(imageURL, @"http://example.com/foo@2x.jpg", @"http://example.com/foo@2x.jpg") -TEST_URL(imageURLWithSpaces, @"http://example.com/blah foo@2x.jpg", @"http://example.com/blah%20foo@2x.jpg") - -// Unicode -TEST_URL( - unicodeURL, - @"https://ru.wikipedia.org/wiki/\u0417\u0430\u0433\u043B\u0430\u0432" - "\u043D\u0430\u044F_\u0441\u0442\u0440\u0430\u043D\u0438\u0446\u0430", - @"https://ru.wikipedia.org/wiki/%D0%97%D0%B0%D0%B3%D0%BB%D0%B0%D0%B2" - "%D0%BD%D0%B0%D1%8F_%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0") - -// Data URLs -- (void)testDataURL -{ - NSURL *expectedURL = RCTDataURL(@"text/plain", [@"abcde" dataUsingEncoding:NSUTF8StringEncoding]); - NSURL *testURL = [NSURL URLWithString:@"data:text/plain;base64,YWJjZGU="]; - XCTAssertEqualObjects([testURL absoluteString], [expectedURL absoluteString]); -} - -@end diff --git a/packages/rn-tester/RNTesterUnitTests/RCTConvert_UIColorTests.m b/packages/rn-tester/RNTesterUnitTests/RCTConvert_UIColorTests.m deleted file mode 100644 index d0bfb605dbe7a9..00000000000000 --- a/packages/rn-tester/RNTesterUnitTests/RCTConvert_UIColorTests.m +++ /dev/null @@ -1,201 +0,0 @@ -/* - * 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 - -#import - -@interface RCTConvert_NSColorTests : XCTestCase - -@end - -static BOOL CGColorsAreEqual(CGColorRef color1, CGColorRef color2) -{ - CGFloat rgba1[4]; - CGFloat rgba2[4]; - RCTGetRGBAColorComponents(color1, rgba1); - RCTGetRGBAColorComponents(color2, rgba2); - for (int i = 0; i < 4; i++) { - if (rgba1[i] != rgba2[i]) { - return NO; - } - } - return YES; -} - -@implementation RCTConvert_NSColorTests - -- (void)testColor -{ - id json = RCTJSONParse(@"{ \"semantic\": \"lightTextColor\" }", nil); - UIColor *value = [RCTConvert UIColor:json]; - XCTAssertEqualObjects(value, [UIColor lightTextColor]); -} - -- (void)testColorFailure -{ - id json = RCTJSONParse(@"{ \"semantic\": \"bogusColor\" }", nil); - - __block NSString *errorMessage = nil; - RCTLogFunction defaultLogFunction = RCTGetLogFunction(); - RCTSetLogFunction( - ^(__unused RCTLogLevel level, - __unused RCTLogSource source, - __unused NSString *fileName, - __unused NSNumber *lineNumber, - NSString *message) { - errorMessage = message; - }); - - UIColor *value = [RCTConvert UIColor:json]; - - RCTSetLogFunction(defaultLogFunction); - - XCTAssertEqualObjects(value, nil); - XCTAssertTrue( - [errorMessage containsString:@"labelColor"]); // the RedBox message will contain a list of the valid color names. -} - -- (void)testFallbackColor -{ - id json = RCTJSONParse(@"{ \"semantic\": \"unitTestFallbackColorIOS\" }", nil); - UIColor *value = [RCTConvert UIColor:json]; - XCTAssertTrue(CGColorsAreEqual([value CGColor], [[UIColor blueColor] CGColor])); -} - -- (void)testDynamicColor -{ - // 0 == 0x00000000 == black - // 16777215 == 0x00FFFFFF == white - id json = RCTJSONParse(@"{ \"dynamic\": { \"light\":0, \"dark\":16777215 } }", nil); - UIColor *value = [RCTConvert UIColor:json]; - XCTAssertNotNil(value); - - id savedTraitCollection = [UITraitCollection currentTraitCollection]; - - [UITraitCollection - setCurrentTraitCollection:[UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleLight]]; - CGFloat rgba[4]; - RCTGetRGBAColorComponents([value CGColor], rgba); - XCTAssertEqual(rgba[0], 0); - XCTAssertEqual(rgba[1], 0); - XCTAssertEqual(rgba[2], 0); - XCTAssertEqual(rgba[3], 0); - - [UITraitCollection - setCurrentTraitCollection:[UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleDark]]; - RCTGetRGBAColorComponents([value CGColor], rgba); - XCTAssertEqual(rgba[0], 1); - XCTAssertEqual(rgba[1], 1); - XCTAssertEqual(rgba[2], 1); - XCTAssertEqual(rgba[3], 0); - - [UITraitCollection setCurrentTraitCollection:savedTraitCollection]; -} - -- (void)testCompositeDynamicColor -{ - id json = RCTJSONParse( - @"{ \"dynamic\": { \"light\": { \"semantic\": \"systemRedColor\" }, \"dark\":{ \"semantic\": \"systemBlueColor\" } } }", - nil); - UIColor *value = [RCTConvert UIColor:json]; - XCTAssertNotNil(value); - - id savedTraitCollection = [UITraitCollection currentTraitCollection]; - - [UITraitCollection - setCurrentTraitCollection:[UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleLight]]; - - XCTAssertTrue(CGColorsAreEqual([value CGColor], [[UIColor systemRedColor] CGColor])); - - [UITraitCollection - setCurrentTraitCollection:[UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleDark]]; - - XCTAssertTrue(CGColorsAreEqual([value CGColor], [[UIColor systemBlueColor] CGColor])); - - [UITraitCollection setCurrentTraitCollection:savedTraitCollection]; -} - -- (void)testGenerateFallbacks -{ - NSDictionary *semanticColors = @{ - // https://developer.apple.com/documentation/uikit/uicolor/ui_element_colors - // Label Colors - @"labelColor" : @(0xFF000000), - @"secondaryLabelColor" : @(0x993c3c43), - @"tertiaryLabelColor" : @(0x4c3c3c43), - @"quaternaryLabelColor" : @(0x2d3c3c43), - // Fill Colors - @"systemFillColor" : @(0x33787880), - @"secondarySystemFillColor" : @(0x28787880), - @"tertiarySystemFillColor" : @(0x1e767680), - @"quaternarySystemFillColor" : @(0x14747480), - // Text Colors - @"placeholderTextColor" : @(0x4c3c3c43), - // Standard Content Background Colors - @"systemBackgroundColor" : @(0xFFffffff), - @"secondarySystemBackgroundColor" : @(0xFFf2f2f7), - @"tertiarySystemBackgroundColor" : @(0xFFffffff), - // Grouped Content Background Colors - @"systemGroupedBackgroundColor" : @(0xFFf2f2f7), - @"secondarySystemGroupedBackgroundColor" : @(0xFFffffff), - @"tertiarySystemGroupedBackgroundColor" : @(0xFFf2f2f7), - // Separator Colors - @"separatorColor" : @(0x493c3c43), - @"opaqueSeparatorColor" : @(0xFFc6c6c8), - // Link Color - @"linkColor" : @(0xFF007aff), - // https://developer.apple.com/documentation/uikit/uicolor/standard_colors - // Adaptable Colors - @"systemBrownColor" : @(0xFFa2845e), - @"systemIndigoColor" : @(0xFF5856d6), - // Adaptable Gray Colors - @"systemGray2Color" : @(0xFFaeaeb2), - @"systemGray3Color" : @(0xFFc7c7cc), - @"systemGray4Color" : @(0xFFd1d1d6), - @"systemGray5Color" : @(0xFFe5e5ea), - @"systemGray6Color" : @(0xFFf2f2f7), - // Clear Color - @"clearColor" : @(0x00000000), - }; - - id savedTraitCollection = nil; - - savedTraitCollection = [UITraitCollection currentTraitCollection]; - - [UITraitCollection - setCurrentTraitCollection:[UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleLight]]; - - for (NSString *semanticColor in semanticColors) { - id json = RCTJSONParse([NSString stringWithFormat:@"{ \"semantic\": \"%@\" }", semanticColor], nil); - UIColor *value = [RCTConvert UIColor:json]; - XCTAssertNotNil(value); - - NSNumber *fallback = [semanticColors objectForKey:semanticColor]; - NSUInteger rgbValue = [fallback unsignedIntegerValue]; - NSUInteger alpha1 = ((rgbValue & 0xFF000000) >> 24); - NSUInteger red1 = ((rgbValue & 0x00FF0000) >> 16); - NSUInteger green1 = ((rgbValue & 0x0000FF00) >> 8); - NSUInteger blue1 = ((rgbValue & 0x000000FF) >> 0); - - CGFloat rgba[4]; - RCTGetRGBAColorComponents([value CGColor], rgba); - NSUInteger red2 = rgba[0] * 255; - NSUInteger green2 = rgba[1] * 255; - NSUInteger blue2 = rgba[2] * 255; - NSUInteger alpha2 = rgba[3] * 255; - - XCTAssertEqual(red1, red2); - XCTAssertEqual(green1, green2); - XCTAssertEqual(blue1, blue2); - XCTAssertEqual(alpha1, alpha2); - } - - [UITraitCollection setCurrentTraitCollection:savedTraitCollection]; -} - -@end diff --git a/packages/rn-tester/RNTesterUnitTests/RCTConvert_YGValueTests.m b/packages/rn-tester/RNTesterUnitTests/RCTConvert_YGValueTests.m deleted file mode 100644 index 3f21b46d4e156d..00000000000000 --- a/packages/rn-tester/RNTesterUnitTests/RCTConvert_YGValueTests.m +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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 - -#import - -@interface RCTConvert_YGValueTests : XCTestCase - -@end - -@implementation RCTConvert_YGValueTests - -- (void)testUndefined -{ - YGValue value = [RCTConvert YGValue:nil]; - XCTAssertEqual(value.unit, YGUnitUndefined); -} - -- (void)testNumberPoints -{ - YGValue value = [RCTConvert YGValue:@100]; - XCTAssertEqual(value.unit, YGUnitPoint); - XCTAssertEqual(value.value, 100); -} - -- (void)testStringPercent -{ - YGValue value = [RCTConvert YGValue:@"100%"]; - XCTAssertEqual(value.unit, YGUnitPercent); - XCTAssertEqual(value.value, 100); -} - -@end diff --git a/packages/rn-tester/RNTesterUnitTests/RCTDevMenuTests.m b/packages/rn-tester/RNTesterUnitTests/RCTDevMenuTests.m deleted file mode 100644 index d88042c46d2f45..00000000000000 --- a/packages/rn-tester/RNTesterUnitTests/RCTDevMenuTests.m +++ /dev/null @@ -1,63 +0,0 @@ -/* - * 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 - -#import -#import -#import - -typedef void (^RCTDevMenuAlertActionHandler)(UIAlertAction *action); - -@interface RCTDevMenu () - -- (RCTDevMenuAlertActionHandler)alertActionHandlerForDevItem:(RCTDevMenuItem *)item; - -@end - -@interface RCTDevMenuTests : XCTestCase - -@end - -@implementation RCTDevMenuTests { - RCTBridge *_bridge; -} - -- (void)setUp -{ - [super setUp]; - - NSBundle *bundle = [NSBundle bundleForClass:[self class]]; - _bridge = [[RCTBridge alloc] initWithBundleURL:[bundle URLForResource:@"RNTesterUnitTestsBundle" withExtension:@"js"] - moduleProvider:nil - launchOptions:nil]; - - RCT_RUN_RUNLOOP_WHILE(_bridge.isLoading); -} - -- (void)testShowCreatingActionSheet -{ - XCTAssertFalse([_bridge.devMenu isActionSheetShown]); - [_bridge.devMenu show]; - XCTAssertTrue([_bridge.devMenu isActionSheetShown]); -} - -- (void)testClosingActionSheetAfterAction -{ - for (RCTDevMenuItem *item in _bridge.devMenu.presentedItems) { - RCTDevMenuAlertActionHandler handler = [_bridge.devMenu alertActionHandlerForDevItem:item]; - XCTAssertTrue([_bridge.devMenu isActionSheetShown]); - - handler(nil); - XCTAssertFalse([_bridge.devMenu isActionSheetShown]); - - [_bridge.devMenu show]; - XCTAssertTrue([_bridge.devMenu isActionSheetShown]); - } -} - -@end diff --git a/packages/rn-tester/RNTesterUnitTests/RCTEventDispatcherTests.m b/packages/rn-tester/RNTesterUnitTests/RCTEventDispatcherTests.m deleted file mode 100644 index a8dbec2959aefc..00000000000000 --- a/packages/rn-tester/RNTesterUnitTests/RCTEventDispatcherTests.m +++ /dev/null @@ -1,278 +0,0 @@ -/* - * 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 -#import - -#import "OCMock/OCMock.h" - -#import - -@interface RCTTestEvent : NSObject -@property (atomic, assign, readwrite) BOOL canCoalesce; -@end - -@implementation RCTTestEvent { - NSDictionary *_body; -} - -@synthesize viewTag = _viewTag; -@synthesize eventName = _eventName; -@synthesize coalescingKey = _coalescingKey; - -- (instancetype)initWithViewTag:(NSNumber *)viewTag - eventName:(NSString *)eventName - body:(NSDictionary *)body - coalescingKey:(uint16_t)coalescingKey -{ - if (self = [super init]) { - _viewTag = viewTag; - _eventName = eventName; - _body = body; - _canCoalesce = YES; - _coalescingKey = coalescingKey; - } - return self; -} - -- (id)coalesceWithEvent:(id)newEvent -{ - return newEvent; -} - -+ (NSString *)moduleDotMethod -{ - return @"MyCustomEventemitter.emit"; -} - -- (NSArray *)arguments -{ - return @[ _eventName, _body ]; -} - -@end - -@interface RCTDummyBridge : RCTBridge -- (void)dispatchBlock:(dispatch_block_t)block queue:(dispatch_queue_t)queue; -@end - -@implementation RCTDummyBridge -- (void)dispatchBlock:(dispatch_block_t __unused)block queue:(dispatch_queue_t __unused)queue -{ -} -@end - -@interface RCTEventDispatcherTests : XCTestCase -@end - -@implementation RCTEventDispatcherTests { - id _bridge; - RCTEventDispatcher *_eventDispatcher; - RCTCallableJSModules *_callableJSModules; - - NSString *_eventName; - NSDictionary *_body; - RCTTestEvent *_testEvent; - NSString *_JSMethod; -} - -- (void)setUp -{ - [super setUp]; - - _bridge = [OCMockObject mockForClass:[RCTDummyBridge class]]; - - _callableJSModules = [RCTCallableJSModules new]; - [_callableJSModules setBridge:_bridge]; - - _eventDispatcher = [RCTEventDispatcher new]; - [_eventDispatcher setValue:_bridge forKey:@"bridge"]; - [_eventDispatcher setValue:_callableJSModules forKey:@"callableJSModules"]; - [_eventDispatcher initialize]; - - _eventName = RCTNormalizeInputEventName(@"sampleEvent"); - _body = @{@"foo" : @"bar"}; - _testEvent = [[RCTTestEvent alloc] initWithViewTag:nil eventName:_eventName body:_body coalescingKey:0]; - - _JSMethod = [[_testEvent class] moduleDotMethod]; -} - -- (void)testLegacyEventsAreImmediatelyDispatched -{ - [[_bridge expect] enqueueJSCall:@"RCTDeviceEventEmitter" method:@"emit" args:[_testEvent arguments] completion:NULL]; - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - [_eventDispatcher sendDeviceEventWithName:_eventName body:_body]; -#pragma clang diagnostic pop - - [_bridge verify]; -} - -- (void)testNonCoalescingEventIsImmediatelyDispatched -{ - _testEvent.canCoalesce = NO; - - [[_bridge expect] dispatchBlock:OCMOCK_ANY queue:RCTJSThread]; - - [_eventDispatcher sendEvent:_testEvent]; - - [_bridge verify]; -} - -- (void)testCoalescingEventIsImmediatelyDispatched -{ - _testEvent.canCoalesce = YES; - - [[_bridge expect] dispatchBlock:OCMOCK_ANY queue:RCTJSThread]; - - [_eventDispatcher sendEvent:_testEvent]; - - [_bridge verify]; -} - -- (void)testMultipleEventsResultInOnlyOneDispatchAfterTheFirstOne -{ - [[_bridge expect] dispatchBlock:OCMOCK_ANY queue:RCTJSThread]; - [_eventDispatcher sendEvent:_testEvent]; - [_eventDispatcher sendEvent:_testEvent]; - [_eventDispatcher sendEvent:_testEvent]; - [_eventDispatcher sendEvent:_testEvent]; - [_eventDispatcher sendEvent:_testEvent]; - [_bridge verify]; -} - -- (void)testRunningTheDispatchedBlockResultInANewOneBeingEnqueued -{ - __block dispatch_block_t eventsEmittingBlock; - [[_bridge expect] dispatchBlock:[OCMArg checkWithBlock:^(dispatch_block_t block) { - eventsEmittingBlock = block; - return YES; - }] - queue:RCTJSThread]; - [_eventDispatcher sendEvent:_testEvent]; - [_bridge verify]; - - // eventsEmittingBlock would be called when js is no longer busy, which will result in emitting events - [self _expectBridgeJSCall:[[_testEvent class] moduleDotMethod] args:[_testEvent arguments]]; - eventsEmittingBlock(); - [_bridge verify]; - - [[_bridge expect] dispatchBlock:OCMOCK_ANY queue:RCTJSThread]; - [_eventDispatcher sendEvent:_testEvent]; - [_bridge verify]; -} - -- (void)testBasicCoalescingReturnsLastEvent -{ - __block dispatch_block_t eventsEmittingBlock; - [[_bridge expect] dispatchBlock:[OCMArg checkWithBlock:^(dispatch_block_t block) { - eventsEmittingBlock = block; - return YES; - }] - queue:RCTJSThread]; - [self _expectBridgeJSCall:[[_testEvent class] moduleDotMethod] args:[_testEvent arguments]]; - - RCTTestEvent *ignoredEvent = [[RCTTestEvent alloc] initWithViewTag:nil - eventName:_eventName - body:@{@"other" : @"body"} - coalescingKey:0]; - [_eventDispatcher sendEvent:ignoredEvent]; - [_eventDispatcher sendEvent:_testEvent]; - eventsEmittingBlock(); - - [_bridge verify]; -} - -- (void)testDifferentEventTypesDontCoalesce -{ - NSString *firstEventName = RCTNormalizeInputEventName(@"firstEvent"); - RCTTestEvent *firstEvent = [[RCTTestEvent alloc] initWithViewTag:nil - eventName:firstEventName - body:_body - coalescingKey:0]; - - __block dispatch_block_t eventsEmittingBlock; - [[_bridge expect] dispatchBlock:[OCMArg checkWithBlock:^(dispatch_block_t block) { - eventsEmittingBlock = block; - return YES; - }] - queue:RCTJSThread]; - [self _expectBridgeJSCall:[[_testEvent class] moduleDotMethod] args:[firstEvent arguments]]; - [self _expectBridgeJSCall:[[_testEvent class] moduleDotMethod] args:[_testEvent arguments]]; - - [_eventDispatcher sendEvent:firstEvent]; - [_eventDispatcher sendEvent:_testEvent]; - eventsEmittingBlock(); - - [_bridge verify]; -} - -- (void)testDifferentViewTagsDontCoalesce -{ - RCTTestEvent *firstEvent = [[RCTTestEvent alloc] initWithViewTag:@(1) - eventName:_eventName - body:_body - coalescingKey:0]; - RCTTestEvent *secondEvent = [[RCTTestEvent alloc] initWithViewTag:@(2) - eventName:_eventName - body:_body - coalescingKey:0]; - - __block dispatch_block_t eventsEmittingBlock; - [[_bridge expect] dispatchBlock:[OCMArg checkWithBlock:^(dispatch_block_t block) { - eventsEmittingBlock = block; - return YES; - }] - queue:RCTJSThread]; - [self _expectBridgeJSCall:[[firstEvent class] moduleDotMethod] args:[firstEvent arguments]]; - [self _expectBridgeJSCall:[[secondEvent class] moduleDotMethod] args:[secondEvent arguments]]; - - [_eventDispatcher sendEvent:firstEvent]; - [_eventDispatcher sendEvent:secondEvent]; - eventsEmittingBlock(); - - [_bridge verify]; -} - -- (void)testSameEventTypesWithDifferentCoalesceKeysDontCoalesce -{ - NSString *eventName = RCTNormalizeInputEventName(@"firstEvent"); - RCTTestEvent *firstEvent = [[RCTTestEvent alloc] initWithViewTag:nil eventName:eventName body:_body coalescingKey:0]; - RCTTestEvent *secondEvent = [[RCTTestEvent alloc] initWithViewTag:nil eventName:eventName body:_body coalescingKey:1]; - - __block dispatch_block_t eventsEmittingBlock; - [[_bridge expect] dispatchBlock:[OCMArg checkWithBlock:^(dispatch_block_t block) { - eventsEmittingBlock = block; - return YES; - }] - queue:RCTJSThread]; - [self _expectBridgeJSCall:[[_testEvent class] moduleDotMethod] args:[firstEvent arguments]]; - [self _expectBridgeJSCall:[[_testEvent class] moduleDotMethod] args:[secondEvent arguments]]; - - [_eventDispatcher sendEvent:firstEvent]; - [_eventDispatcher sendEvent:secondEvent]; - [_eventDispatcher sendEvent:firstEvent]; - [_eventDispatcher sendEvent:secondEvent]; - [_eventDispatcher sendEvent:secondEvent]; - [_eventDispatcher sendEvent:firstEvent]; - [_eventDispatcher sendEvent:firstEvent]; - - eventsEmittingBlock(); - - [_bridge verify]; -} - -- (void)_expectBridgeJSCall:(NSString *)moduleDotMethod args:(NSArray *)args -{ - NSArray *const components = [moduleDotMethod componentsSeparatedByString:@"."]; - NSString *const moduleName = components[0]; - NSString *const methodName = components[1]; - [[_bridge expect] enqueueJSCall:moduleName method:methodName args:args completion:NULL]; -} - -@end diff --git a/packages/rn-tester/RNTesterUnitTests/RCTEventEmitterTests.m b/packages/rn-tester/RNTesterUnitTests/RCTEventEmitterTests.m deleted file mode 100644 index 43db9d015fdf84..00000000000000 --- a/packages/rn-tester/RNTesterUnitTests/RCTEventEmitterTests.m +++ /dev/null @@ -1,72 +0,0 @@ -/* - * 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 -#import - -#pragma mark - Faulty EventEmitter - -@interface RCTFaultyEventEmitter : RCTEventEmitter -@end - -@implementation RCTFaultyEventEmitter { - NSString *_capturedMessage; -} - -- (NSString *)capturedMessage -{ - return _capturedMessage; -} - -- (void)_log:(NSString *)message -{ - _capturedMessage = message; -} -@end - -#pragma mark - Proper EventEmitter - -@interface RCTProperEventEmitter : RCTEventEmitter -@end - -@implementation RCTProperEventEmitter - -- (NSArray *)supportedEvents -{ - return @[ @"myEvent" ]; -} -@end - -#pragma mark - Tests Code - -@interface RCTEventEmitterTests : XCTestCase - -@end - -@implementation RCTEventEmitterTests - -- (void)testEventEmitterSubclass_whenFaultySubclassInvokesSupportedEvents_raiseException -{ - RCTEventEmitter *emitter = [[RCTFaultyEventEmitter alloc] init]; - - NSArray *events = emitter.supportedEvents; - XCTAssertNil(events); - XCTAssertEqualObjects( - ((RCTFaultyEventEmitter *)emitter).capturedMessage, - @"RCTFaultyEventEmitter must implement the supportedEvents method"); -} - -- (void)testEventEmitterSubclass_whenProperSubclassInvokesSupportedEvents_itreturnsTheEvents -{ - RCTEventEmitter *emitter = [[RCTProperEventEmitter alloc] init]; - - NSArray *events = emitter.supportedEvents; - - XCTAssertEqualObjects(events, @[ @"myEvent" ]); -} - -@end diff --git a/packages/rn-tester/RNTesterUnitTests/RCTFontTests.m b/packages/rn-tester/RNTesterUnitTests/RCTFontTests.m deleted file mode 100644 index fc686c65f25024..00000000000000 --- a/packages/rn-tester/RNTesterUnitTests/RCTFontTests.m +++ /dev/null @@ -1,222 +0,0 @@ -/* - * 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 -#import - -#import - -@interface RCTFontTests : XCTestCase - -@end - -@implementation RCTFontTests - -// It can happen (particularly in tvOS simulator) that expected and result font objects -// will be different objects, but the same font, so this macro now explicitly -// checks that fontName (which includes the style) and pointSize are equal. -#define RCTAssertEqualFonts(font1, font2) \ - { \ - XCTAssertEqualObjects(font1.fontName, font2.fontName); \ - XCTAssertEqual(font1.pointSize, font2.pointSize); \ - } - -- (void)testWeight -{ - { - UIFont *expected = [UIFont systemFontOfSize:14 weight:UIFontWeightBold]; - UIFont *result = [RCTConvert UIFont:@{@"fontWeight" : @"bold"}]; - RCTAssertEqualFonts(expected, result); - } - { - UIFont *expected = [UIFont systemFontOfSize:14 weight:UIFontWeightMedium]; - UIFont *result = [RCTConvert UIFont:@{@"fontWeight" : @"500"}]; - RCTAssertEqualFonts(expected, result); - } - { - UIFont *expected = [UIFont systemFontOfSize:14 weight:UIFontWeightUltraLight]; - UIFont *result = [RCTConvert UIFont:@{@"fontWeight" : @"100"}]; - RCTAssertEqualFonts(expected, result); - } - { - UIFont *expected = [UIFont systemFontOfSize:14 weight:UIFontWeightRegular]; - UIFont *result = [RCTConvert UIFont:@{@"fontWeight" : @"normal"}]; - RCTAssertEqualFonts(expected, result); - } -} - -- (void)testSize -{ - { - UIFont *expected = [UIFont systemFontOfSize:18.5]; - UIFont *result = [RCTConvert UIFont:@{@"fontSize" : @18.5}]; - RCTAssertEqualFonts(expected, result); - } -} - -- (void)testFamily -{ -#if !TARGET_OS_TV - { - UIFont *expected = [UIFont fontWithName:@"Cochin" size:14]; - UIFont *result = [RCTConvert UIFont:@{@"fontFamily" : @"Cochin"}]; - RCTAssertEqualFonts(expected, result); - } -#endif - { - UIFont *expected = [UIFont fontWithName:@"HelveticaNeue" size:14]; - UIFont *result = [RCTConvert UIFont:@{@"fontFamily" : @"Helvetica Neue"}]; - RCTAssertEqualFonts(expected, result); - } - { - UIFont *expected = [UIFont fontWithName:@"HelveticaNeue-Italic" size:14]; - UIFont *result = [RCTConvert UIFont:@{@"fontFamily" : @"HelveticaNeue-Italic"}]; - RCTAssertEqualFonts(expected, result); - } -} - -- (void)testStyle -{ - { - UIFont *font = [UIFont systemFontOfSize:14]; - UIFontDescriptor *fontDescriptor = [font fontDescriptor]; - UIFontDescriptorSymbolicTraits symbolicTraits = fontDescriptor.symbolicTraits; - symbolicTraits |= UIFontDescriptorTraitItalic; - fontDescriptor = [fontDescriptor fontDescriptorWithSymbolicTraits:symbolicTraits]; - UIFont *expected = [UIFont fontWithDescriptor:fontDescriptor size:14]; - UIFont *result = [RCTConvert UIFont:@{@"fontStyle" : @"italic"}]; - RCTAssertEqualFonts(expected, result); - } - { - UIFont *expected = [UIFont systemFontOfSize:14]; - UIFont *result = [RCTConvert UIFont:@{@"fontStyle" : @"normal"}]; - RCTAssertEqualFonts(expected, result); - } -} - -- (void)testStyleAndWeight -{ - { - UIFont *font = [UIFont systemFontOfSize:14 weight:UIFontWeightUltraLight]; - UIFontDescriptor *fontDescriptor = [font fontDescriptor]; - UIFontDescriptorSymbolicTraits symbolicTraits = fontDescriptor.symbolicTraits; - symbolicTraits |= UIFontDescriptorTraitItalic; - fontDescriptor = [fontDescriptor fontDescriptorWithSymbolicTraits:symbolicTraits]; - UIFont *expected = [UIFont fontWithDescriptor:fontDescriptor size:14]; - UIFont *result = [RCTConvert UIFont:@{@"fontStyle" : @"italic", @"fontWeight" : @"100"}]; - RCTAssertEqualFonts(expected, result); - } - { - UIFont *font = [UIFont systemFontOfSize:14 weight:UIFontWeightBold]; - UIFontDescriptor *fontDescriptor = [font fontDescriptor]; - UIFontDescriptorSymbolicTraits symbolicTraits = fontDescriptor.symbolicTraits; - symbolicTraits |= UIFontDescriptorTraitItalic; - fontDescriptor = [fontDescriptor fontDescriptorWithSymbolicTraits:symbolicTraits]; - UIFont *expected = [UIFont fontWithDescriptor:fontDescriptor size:14]; - UIFont *result = [RCTConvert UIFont:@{@"fontStyle" : @"italic", @"fontWeight" : @"bold"}]; - RCTAssertEqualFonts(expected, result); - } -} - -- (void)testFamilyAndWeight -{ - { - UIFont *expected = [UIFont fontWithName:@"HelveticaNeue-Bold" size:14]; - UIFont *result = [RCTConvert UIFont:@{@"fontFamily" : @"Helvetica Neue", @"fontWeight" : @"bold"}]; - RCTAssertEqualFonts(expected, result); - } - { - UIFont *expected = [UIFont fontWithName:@"HelveticaNeue" size:14]; - UIFont *result = [RCTConvert UIFont:@{@"fontFamily" : @"HelveticaNeue-Bold", @"fontWeight" : @"normal"}]; - RCTAssertEqualFonts(expected, result); - } -#if !TARGET_OS_TV - { - UIFont *expected = [UIFont fontWithName:@"Cochin-Bold" size:14]; - UIFont *result = [RCTConvert UIFont:@{@"fontFamily" : @"Cochin", @"fontWeight" : @"700"}]; - RCTAssertEqualFonts(expected, result); - } - { - UIFont *expected = [UIFont fontWithName:@"Cochin" size:14]; - UIFont *result = [RCTConvert UIFont:@{@"fontFamily" : @"Cochin", @"fontWeight" : @"100"}]; - RCTAssertEqualFonts(expected, result); - } -#endif -} - -- (void)testFamilyAndStyle -{ - { - UIFont *expected = [UIFont fontWithName:@"HelveticaNeue-Italic" size:14]; - UIFont *result = [RCTConvert UIFont:@{@"fontFamily" : @"Helvetica Neue", @"fontStyle" : @"italic"}]; - RCTAssertEqualFonts(expected, result); - } - { - UIFont *expected = [UIFont fontWithName:@"HelveticaNeue" size:14]; - UIFont *result = [RCTConvert UIFont:@{@"fontFamily" : @"HelveticaNeue-Italic", @"fontStyle" : @"normal"}]; - RCTAssertEqualFonts(expected, result); - } -} - -- (void)testFamilyStyleAndWeight -{ - { - UIFont *expected = [UIFont fontWithName:@"HelveticaNeue-LightItalic" size:14]; - UIFont *result = - [RCTConvert UIFont:@{@"fontFamily" : @"Helvetica Neue", @"fontStyle" : @"italic", @"fontWeight" : @"300"}]; - RCTAssertEqualFonts(expected, result); - } - { - UIFont *expected = [UIFont fontWithName:@"HelveticaNeue-Bold" size:14]; - UIFont *result = [RCTConvert - UIFont:@{@"fontFamily" : @"HelveticaNeue-Italic", @"fontStyle" : @"normal", @"fontWeight" : @"bold"}]; - RCTAssertEqualFonts(expected, result); - } - { - UIFont *expected = [UIFont fontWithName:@"HelveticaNeue" size:14]; - UIFont *result = [RCTConvert - UIFont:@{@"fontFamily" : @"HelveticaNeue-Italic", @"fontStyle" : @"normal", @"fontWeight" : @"normal"}]; - RCTAssertEqualFonts(expected, result); - } -} - -- (void)testVariant -{ - { - UIFont *expected = [UIFont monospacedDigitSystemFontOfSize:14 weight:UIFontWeightRegular]; - UIFont *result = [RCTConvert UIFont:@{@"fontVariant" : @[ @"tabular-nums" ]}]; - RCTAssertEqualFonts(expected, result); - } - { - UIFont *monospaceFont = [UIFont monospacedDigitSystemFontOfSize:14 weight:UIFontWeightRegular]; - UIFontDescriptor *fontDescriptor = [monospaceFont.fontDescriptor fontDescriptorByAddingAttributes:@{ - UIFontDescriptorFeatureSettingsAttribute : @[ @{ - UIFontFeatureTypeIdentifierKey : @(kLowerCaseType), - UIFontFeatureSelectorIdentifierKey : @(kLowerCaseSmallCapsSelector), - } ] - }]; - UIFont *expected = [UIFont fontWithDescriptor:fontDescriptor size:14]; - UIFont *result = [RCTConvert UIFont:@{@"fontVariant" : @[ @"tabular-nums", @"small-caps" ]}]; - RCTAssertEqualFonts(expected, result); - } -} - -- (void)testInvalidFont -{ - { - UIFont *expected = [UIFont systemFontOfSize:14]; - UIFont *result = [RCTConvert UIFont:@{@"fontFamily" : @"foobar"}]; - RCTAssertEqualFonts(expected, result); - } - { - UIFont *expected = [UIFont systemFontOfSize:14 weight:UIFontWeightBold]; - UIFont *result = [RCTConvert UIFont:@{@"fontFamily" : @"foobar", @"fontWeight" : @"bold"}]; - RCTAssertEqualFonts(expected, result); - } -} - -@end diff --git a/packages/rn-tester/RNTesterUnitTests/RCTFormatErrorTests.m b/packages/rn-tester/RNTesterUnitTests/RCTFormatErrorTests.m deleted file mode 100644 index 70a972686cc7ac..00000000000000 --- a/packages/rn-tester/RNTesterUnitTests/RCTFormatErrorTests.m +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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 - -#import - -@interface RCTFormatErrorTests : XCTestCase - -@end - -@implementation RCTFormatErrorTests - -- (void)testSymbolication -{ - NSArray *> *stackTrace = @[ - @{@"methodName" : @"method_from_bundle", @"column" : @11, @"lineNumber" : @7, @"file" : @"Fb4aBundle.js"}, - @{@"methodName" : @"method_from_ram_bundle", @"column" : @13, @"lineNumber" : @18, @"file" : @"199.js"}, - @{ - @"methodName" : @"method_from_ram_bundle_with_address", - @"column" : @13, - @"lineNumber" : @18, - @"file" : @"address at 199.js" - }, - @{@"methodName" : @"method_from_segment", @"column" : @18, @"lineNumber" : @9, @"file" : @"seg-1.js"}, - @{ - @"methodName" : @"method_from_segment_with_address", - @"column" : @18, - @"lineNumber" : @9, - @"file" : @"address at seg-1.js" - }, - @{@"methodName" : @"method_from_ram_segment", @"column" : @20, @"lineNumber" : @10, @"file" : @"seg-3_198.js"}, - @{ - @"methodName" : @"method_from_ram_segment_with_address", - @"column" : @20, - @"lineNumber" : @10, - @"file" : @"address at seg-3_198.js" - } - ]; - NSString *message = RCTFormatError(@"Error", stackTrace, 0); - XCTAssertEqualObjects( - message, - @"Error, stack:\n" - "method_from_bundle@7:11\n" - "method_from_ram_bundle@199.js:18:13\n" - "method_from_ram_bundle_with_address@199.js:18:13\n" - "method_from_segment@seg-1.js:9:18\n" - "method_from_segment_with_address@seg-1.js:9:18\n" - "method_from_ram_segment@seg-3_198.js:10:20\n" - "method_from_ram_segment_with_address@seg-3_198.js:10:20\n"); -} - -@end diff --git a/packages/rn-tester/RNTesterUnitTests/RCTGzipTests.m b/packages/rn-tester/RNTesterUnitTests/RCTGzipTests.m deleted file mode 100644 index a24d9972be778d..00000000000000 --- a/packages/rn-tester/RNTesterUnitTests/RCTGzipTests.m +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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 - -#import -#import -#import - -extern BOOL RCTIsGzippedData(NSData *data); - -@interface RCTNetworking (Private) - -- (void)buildRequest:(NSDictionary *)query completionBlock:(void (^)(NSURLRequest *request))block; - -@end - -@interface RCTGzipTests : XCTestCase - -@end - -@implementation RCTGzipTests - -- (void)testGzip -{ - // set up data - NSString *inputString = @"Hello World!"; - NSData *inputData = [inputString dataUsingEncoding:NSUTF8StringEncoding]; - - // compress - NSData *outputData = RCTGzipData(inputData, -1); - XCTAssertTrue(RCTIsGzippedData(outputData)); -} - -- (void)testDontRezipZippedData -{ - // set up data - NSString *inputString = @"Hello World!"; - NSData *inputData = [inputString dataUsingEncoding:NSUTF8StringEncoding]; - - // compress - NSData *compressedData = RCTGzipData(inputData, -1); - inputString = [[NSString alloc] initWithData:compressedData encoding:NSUTF8StringEncoding]; - - // compress again - NSData *outputData = RCTGzipData(inputData, -1); - NSString *outputString = [[NSString alloc] initWithData:outputData encoding:NSUTF8StringEncoding]; - XCTAssertEqualObjects(outputString, inputString); -} - -- (void)testRequestBodyEncoding -{ - NSDictionary *query = @{ - @"url" : @"http://example.com", - @"method" : @"POST", - @"data" : @{@"string" : @"Hello World"}, - @"headers" : @{@"Content-Encoding" : @"gzip"}, - }; - - RCTNetworking *networker = [RCTNetworking new]; - [networker setValue:dispatch_get_main_queue() forKey:@"methodQueue"]; - __block NSURLRequest *request = nil; - [networker buildRequest:query - completionBlock:^(NSURLRequest *_request) { - request = _request; - }]; - - RCT_RUN_RUNLOOP_WHILE(request == nil); - - XCTAssertNotNil(request); - XCTAssertNotNil(request.HTTPBody); - XCTAssertTrue(RCTIsGzippedData(request.HTTPBody)); -} - -@end diff --git a/packages/rn-tester/RNTesterUnitTests/RCTImageLoaderHelpers.h b/packages/rn-tester/RNTesterUnitTests/RCTImageLoaderHelpers.h deleted file mode 100644 index 58ebca1a4f944b..00000000000000 --- a/packages/rn-tester/RNTesterUnitTests/RCTImageLoaderHelpers.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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 - -typedef BOOL (^RCTImageURLLoaderCanLoadImageURLHandler)(NSURL *requestURL); -typedef RCTImageLoaderCancellationBlock (^RCTImageURLLoaderLoadImageURLHandler)( - NSURL *imageURL, - CGSize size, - CGFloat scale, - RCTResizeMode resizeMode, - RCTImageLoaderProgressBlock progressHandler, - RCTImageLoaderCompletionBlock completionHandler); - -@interface RCTConcreteImageURLLoader : NSObject - -- (instancetype)initWithPriority:(float)priority - canLoadImageURLHandler:(RCTImageURLLoaderCanLoadImageURLHandler)canLoadImageURLHandler - loadImageURLHandler:(RCTImageURLLoaderLoadImageURLHandler)loadImageURLHandler; - -@end - -typedef BOOL (^RCTImageDataDecoderCanDecodeImageDataHandler)(NSData *imageData); -typedef RCTImageLoaderCancellationBlock (^RCTImageDataDecoderDecodeImageDataHandler)( - NSData *imageData, - CGSize size, - CGFloat scale, - RCTResizeMode resizeMode, - RCTImageLoaderCompletionBlock completionHandler); - -@interface RCTConcreteImageDecoder : NSObject - -- (instancetype)initWithPriority:(float)priority - canDecodeImageDataHandler:(RCTImageDataDecoderCanDecodeImageDataHandler)canDecodeImageDataHandler - decodeImageDataHandler:(RCTImageDataDecoderDecodeImageDataHandler)decodeImageDataHandler; - -@end - -#define _RCTDefineImageHandler(SUPERCLASS, CLASS_NAME) \ - @interface CLASS_NAME : SUPERCLASS \ - @end \ - @implementation CLASS_NAME \ - RCT_EXPORT_MODULE() @end - -#define RCTDefineImageURLLoader(CLASS_NAME) _RCTDefineImageHandler(RCTConcreteImageURLLoader, CLASS_NAME) - -#define RCTDefineImageDecoder(CLASS_NAME) _RCTDefineImageHandler(RCTConcreteImageDecoder, CLASS_NAME) diff --git a/packages/rn-tester/RNTesterUnitTests/RCTImageLoaderHelpers.m b/packages/rn-tester/RNTesterUnitTests/RCTImageLoaderHelpers.m deleted file mode 100644 index 79649e0405ba12..00000000000000 --- a/packages/rn-tester/RNTesterUnitTests/RCTImageLoaderHelpers.m +++ /dev/null @@ -1,110 +0,0 @@ -/* - * 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 "RCTImageLoaderHelpers.h" - -@implementation RCTConcreteImageURLLoader { - RCTImageURLLoaderCanLoadImageURLHandler _canLoadImageURLHandler; - RCTImageURLLoaderLoadImageURLHandler _loadImageURLHandler; - float _priority; -} - -+ (NSString *)moduleName -{ - return nil; -} - -- (instancetype)init -{ - return nil; -} - -- (instancetype)initWithPriority:(float)priority - canLoadImageURLHandler:(RCTImageURLLoaderCanLoadImageURLHandler)canLoadImageURLHandler - loadImageURLHandler:(RCTImageURLLoaderLoadImageURLHandler)loadImageURLHandler -{ - if ((self = [super init])) { - _canLoadImageURLHandler = [canLoadImageURLHandler copy]; - _loadImageURLHandler = [loadImageURLHandler copy]; - _priority = priority; - } - - return self; -} - -- (BOOL)canLoadImageURL:(NSURL *)requestURL -{ - return _canLoadImageURLHandler(requestURL); -} - -- (RCTImageLoaderCancellationBlock)loadImageForURL:(NSURL *)imageURL - size:(CGSize)size - scale:(CGFloat)scale - resizeMode:(RCTResizeMode)resizeMode - progressHandler:(RCTImageLoaderProgressBlock)progressHandler - partialLoadHandler:(__unused RCTImageLoaderPartialLoadBlock)partialLoadHandler - completionHandler:(RCTImageLoaderCompletionBlock)completionHandler -{ - return _loadImageURLHandler(imageURL, size, scale, resizeMode, progressHandler, completionHandler); -} - -- (float)loaderPriority -{ - return _priority; -} - -@end - -@implementation RCTConcreteImageDecoder { - RCTImageDataDecoderCanDecodeImageDataHandler _canDecodeImageDataHandler; - RCTImageDataDecoderDecodeImageDataHandler _decodeImageDataHandler; - float _priority; -} - -+ (NSString *)moduleName -{ - return nil; -} - -- (instancetype)init -{ - return nil; -} - -- (instancetype)initWithPriority:(float)priority - canDecodeImageDataHandler:(RCTImageDataDecoderCanDecodeImageDataHandler)canDecodeImageDataHandler - decodeImageDataHandler:(RCTImageDataDecoderDecodeImageDataHandler)decodeImageDataHandler -{ - if ((self = [super init])) { - _canDecodeImageDataHandler = [canDecodeImageDataHandler copy]; - _decodeImageDataHandler = [decodeImageDataHandler copy]; - _priority = priority; - } - - return self; -} - -- (BOOL)canDecodeImageData:(NSData *)imageData -{ - return _canDecodeImageDataHandler(imageData); -} - -- (RCTImageLoaderCancellationBlock)decodeImageData:(NSData *)imageData - size:(CGSize)size - scale:(CGFloat)scale - resizeMode:(RCTResizeMode)resizeMode - completionHandler:(RCTImageLoaderCompletionBlock)completionHandler -{ - return _decodeImageDataHandler(imageData, size, scale, resizeMode, completionHandler); -} - -- (float)decoderPriority -{ - return _priority; -} - -@end diff --git a/packages/rn-tester/RNTesterUnitTests/RCTImageLoaderTests.m b/packages/rn-tester/RNTesterUnitTests/RCTImageLoaderTests.m deleted file mode 100644 index 6c58e9cb26d0c1..00000000000000 --- a/packages/rn-tester/RNTesterUnitTests/RCTImageLoaderTests.m +++ /dev/null @@ -1,233 +0,0 @@ -/* - * 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 - -#import -#import - -#import "RCTImageLoaderHelpers.h" - -unsigned char blackGIF[] = {0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x01, 0x00, 0x01, 0x00, 0x80, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x2c, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x01, 0x00, 0x00, 0x02, 0x02, 0x44, 0x01, 0x00, 0x3b}; - -RCTDefineImageURLLoader(RCTImageLoaderTestsURLLoader1) RCTDefineImageURLLoader(RCTImageLoaderTestsURLLoader2) - RCTDefineImageDecoder(RCTImageLoaderTestsDecoder1) RCTDefineImageDecoder(RCTImageLoaderTestsDecoder2) - - @interface RCTImageLoaderTests : XCTestCase - -@end - -@implementation RCTImageLoaderTests { - NSURL *_bundleURL; -} - -- (void)setUp -{ - NSBundle *bundle = [NSBundle bundleForClass:[self class]]; - _bundleURL = [bundle URLForResource:@"RNTesterUnitTestsBundle" withExtension:@"js"]; -} - -- (void)testImageLoading -{ - UIImage *image = [UIImage new]; - - id loader = [[RCTImageLoaderTestsURLLoader1 alloc] initWithPriority:1.0 - canLoadImageURLHandler:^BOOL(__unused NSURL *requestURL) { - return YES; - } - loadImageURLHandler:^RCTImageLoaderCancellationBlock( - __unused NSURL *imageURL, - __unused CGSize size, - __unused CGFloat scale, - __unused RCTResizeMode resizeMode, - RCTImageLoaderProgressBlock progressHandler, - RCTImageLoaderCompletionBlock completionHandler) { - progressHandler(1, 1); - completionHandler(nil, image); - return nil; - }]; - - NS_VALID_UNTIL_END_OF_SCOPE RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:_bundleURL - moduleProvider:^{ - return @[ loader ]; - } - launchOptions:nil]; - - NSURLRequest *urlRequest = - [NSURLRequest requestWithURL:[NSURL URLWithString:@"https://reactnative.dev/img/opengraph.png"]]; - [[bridge moduleForClass:[RCTImageLoader class]] loadImageWithURLRequest:urlRequest - size:CGSizeMake(100, 100) - scale:1.0 - clipped:YES - resizeMode:RCTResizeModeContain - progressBlock:^(int64_t progress, int64_t total) { - XCTAssertEqual(progress, 1); - XCTAssertEqual(total, 1); - } - partialLoadBlock:^(UIImage *loadedImage) { - } - completionBlock:^(NSError *loadError, id loadedImage) { - XCTAssertEqualObjects(loadedImage, image); - XCTAssertNil(loadError); - }]; -} - -- (void)testImageLoaderUsesImageURLLoaderWithHighestPriority -{ - UIImage *image = [UIImage new]; - - id loader1 = [[RCTImageLoaderTestsURLLoader1 alloc] initWithPriority:1.0 - canLoadImageURLHandler:^BOOL(__unused NSURL *requestURL) { - return YES; - } - loadImageURLHandler:^RCTImageLoaderCancellationBlock( - __unused NSURL *imageURL, - __unused CGSize size, - __unused CGFloat scale, - __unused RCTResizeMode resizeMode, - RCTImageLoaderProgressBlock progressHandler, - RCTImageLoaderCompletionBlock completionHandler) { - progressHandler(1, 1); - completionHandler(nil, image); - return nil; - }]; - - id loader2 = [[RCTImageLoaderTestsURLLoader2 alloc] initWithPriority:0.5 - canLoadImageURLHandler:^BOOL(__unused NSURL *requestURL) { - return YES; - } - loadImageURLHandler:^RCTImageLoaderCancellationBlock( - __unused NSURL *imageURL, - __unused CGSize size, - __unused CGFloat scale, - __unused RCTResizeMode resizeMode, - __unused RCTImageLoaderProgressBlock progressHandler, - __unused RCTImageLoaderCompletionBlock completionHandler) { - XCTFail(@"Should not have used loader2"); - return nil; - }]; - - NS_VALID_UNTIL_END_OF_SCOPE RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:_bundleURL - moduleProvider:^{ - return @[ loader1, loader2 ]; - } - launchOptions:nil]; - - NSURLRequest *urlRequest = - [NSURLRequest requestWithURL:[NSURL URLWithString:@"https://reactnative.dev/img/opengraph.png"]]; - [[bridge moduleForClass:[RCTImageLoader class]] loadImageWithURLRequest:urlRequest - size:CGSizeMake(100, 100) - scale:1.0 - clipped:YES - resizeMode:RCTResizeModeContain - progressBlock:^(int64_t progress, int64_t total) { - XCTAssertEqual(progress, 1); - XCTAssertEqual(total, 1); - } - partialLoadBlock:^(UIImage *loadedImage) { - } - completionBlock:^(NSError *loadError, id loadedImage) { - XCTAssertEqualObjects(loadedImage, image); - XCTAssertNil(loadError); - }]; -} - -- (void)testImageDecoding -{ - NSData *data = [NSData dataWithBytesNoCopy:blackGIF length:sizeof(blackGIF) freeWhenDone:NO]; - UIImage *image = [[UIImage alloc] initWithData:data]; - - id decoder = [[RCTImageLoaderTestsDecoder1 alloc] initWithPriority:1.0 - canDecodeImageDataHandler:^BOOL(__unused NSData *imageData) { - return YES; - } - decodeImageDataHandler:^RCTImageLoaderCancellationBlock( - NSData *imageData, - __unused CGSize size, - __unused CGFloat scale, - __unused RCTResizeMode resizeMode, - RCTImageLoaderCompletionBlock completionHandler) { - XCTAssertEqualObjects(imageData, data); - completionHandler(nil, image); - return nil; - }]; - - NS_VALID_UNTIL_END_OF_SCOPE RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:_bundleURL - moduleProvider:^{ - return @[ decoder ]; - } - launchOptions:nil]; - - RCTImageLoaderCancellationBlock cancelBlock = - [[bridge moduleForClass:[RCTImageLoader class]] decodeImageData:data - size:CGSizeMake(1, 1) - scale:1.0 - clipped:NO - resizeMode:RCTResizeModeStretch - completionBlock:^(NSError *decodeError, id decodedImage) { - XCTAssertEqualObjects(decodedImage, image); - XCTAssertNil(decodeError); - }]; - XCTAssertNotNil(cancelBlock); -} - -- (void)testImageLoaderUsesImageDecoderWithHighestPriority -{ - NSData *data = [NSData dataWithBytesNoCopy:blackGIF length:sizeof(blackGIF) freeWhenDone:NO]; - UIImage *image = [[UIImage alloc] initWithData:data]; - - id decoder1 = [[RCTImageLoaderTestsDecoder1 alloc] initWithPriority:1.0 - canDecodeImageDataHandler:^BOOL(__unused NSData *imageData) { - return YES; - } - decodeImageDataHandler:^RCTImageLoaderCancellationBlock( - NSData *imageData, - __unused CGSize size, - __unused CGFloat scale, - __unused RCTResizeMode resizeMode, - RCTImageLoaderCompletionBlock completionHandler) { - XCTAssertEqualObjects(imageData, data); - completionHandler(nil, image); - return nil; - }]; - - id decoder2 = [[RCTImageLoaderTestsDecoder2 alloc] initWithPriority:0.5 - canDecodeImageDataHandler:^BOOL(__unused NSData *imageData) { - return YES; - } - decodeImageDataHandler:^RCTImageLoaderCancellationBlock( - __unused NSData *imageData, - __unused CGSize size, - __unused CGFloat scale, - __unused RCTResizeMode resizeMode, - __unused RCTImageLoaderCompletionBlock completionHandler) { - XCTFail(@"Should not have used decoder2"); - return nil; - }]; - - NS_VALID_UNTIL_END_OF_SCOPE RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:_bundleURL - moduleProvider:^{ - return @[ decoder1, decoder2 ]; - } - launchOptions:nil]; - - RCTImageLoaderCancellationBlock cancelBlock = - [[bridge moduleForClass:[RCTImageLoader class]] decodeImageData:data - size:CGSizeMake(1, 1) - scale:1.0 - clipped:NO - resizeMode:RCTResizeModeStretch - completionBlock:^(NSError *decodeError, id decodedImage) { - XCTAssertEqualObjects(decodedImage, image); - XCTAssertNil(decodeError); - }]; - XCTAssertNotNil(cancelBlock); -} - -@end diff --git a/packages/rn-tester/RNTesterUnitTests/RCTImageUtilTests.m b/packages/rn-tester/RNTesterUnitTests/RCTImageUtilTests.m deleted file mode 100644 index 8d0fde347fc4b8..00000000000000 --- a/packages/rn-tester/RNTesterUnitTests/RCTImageUtilTests.m +++ /dev/null @@ -1,133 +0,0 @@ -/* - * 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 -#import -#import -#import - -#import - -#define RCTAssertEqualPoints(a, b) \ - { \ - XCTAssertEqual(a.x, b.x); \ - XCTAssertEqual(a.y, b.y); \ - } - -#define RCTAssertEqualSizes(a, b) \ - { \ - XCTAssertEqual(a.width, b.width); \ - XCTAssertEqual(a.height, b.height); \ - } - -#define RCTAssertEqualRects(a, b) \ - { \ - RCTAssertEqualPoints(a.origin, b.origin); \ - RCTAssertEqualSizes(a.size, b.size); \ - } - -@interface RCTImageUtilTests : XCTestCase - -@end - -@implementation RCTImageUtilTests - -- (void)testLandscapeSourceLandscapeTarget -{ - CGSize content = {1000, 100}; - CGSize target = {100, 20}; - - { - CGRect expected = {CGPointZero, {100, 20}}; - CGRect result = RCTTargetRect(content, target, 1, RCTResizeModeStretch); - RCTAssertEqualRects(expected, result); - } - - { - CGRect expected = {{0, 5}, {100, 10}}; - CGRect result = RCTTargetRect(content, target, 1, RCTResizeModeContain); - RCTAssertEqualRects(expected, result); - } - - { - CGRect expected = {{-50, 0}, {200, 20}}; - CGRect result = RCTTargetRect(content, target, 1, RCTResizeModeCover); - RCTAssertEqualRects(expected, result); - } -} - -- (void)testPortraitSourceLandscapeTarget -{ - CGSize content = {10, 100}; - CGSize target = {100, 20}; - - { - CGRect expected = {CGPointZero, {100, 20}}; - CGRect result = RCTTargetRect(content, target, 1, RCTResizeModeStretch); - RCTAssertEqualRects(expected, result); - } - - { - CGRect expected = {{49, 0}, {2, 20}}; - CGRect result = RCTTargetRect(content, target, 1, RCTResizeModeContain); - RCTAssertEqualRects(expected, result); - } - - { - CGRect expected = {{0, -490}, {100, 1000}}; - CGRect result = RCTTargetRect(content, target, 1, RCTResizeModeCover); - RCTAssertEqualRects(expected, result); - } -} - -- (void)testPortraitSourcePortraitTarget -{ - CGSize content = {10, 100}; - CGSize target = {20, 50}; - - { - CGRect expected = {CGPointZero, {20, 50}}; - CGRect result = RCTTargetRect(content, target, 1, RCTResizeModeStretch); - RCTAssertEqualRects(expected, result); - } - - { - CGRect expected = {{7, 0}, {5, 50}}; - CGRect result = RCTTargetRect(content, target, 1, RCTResizeModeContain); - RCTAssertEqualRects(expected, result); - } - - { - CGRect expected = {{0, -75}, {20, 200}}; - CGRect result = RCTTargetRect(content, target, 2, RCTResizeModeCover); - RCTAssertEqualRects(expected, result); - } -} - -- (void)testRounding -{ - CGSize content = {10, 100}; - CGSize target = {20, 50}; - - { - CGRect expected = {{0, -75}, {20, 200}}; - CGRect result = RCTTargetRect(content, target, 1, RCTResizeModeCover); - RCTAssertEqualRects(expected, result); - } -} - -- (void)testScaling -{ - CGSize content = {2, 2}; - CGSize target = {3, 3}; - - CGRect expected = {CGPointZero, {3, 3}}; - CGRect result = RCTTargetRect(content, target, 1, RCTResizeModeStretch); - RCTAssertEqualRects(expected, result); -} - -@end diff --git a/packages/rn-tester/RNTesterUnitTests/RCTJSONTests.m b/packages/rn-tester/RNTesterUnitTests/RCTJSONTests.m deleted file mode 100644 index 32fcbd360c219f..00000000000000 --- a/packages/rn-tester/RNTesterUnitTests/RCTJSONTests.m +++ /dev/null @@ -1,124 +0,0 @@ -/* - * 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 - -#import - -@interface RCTJSONTests : XCTestCase - -@end - -@implementation RCTJSONTests - -- (void)testEncodingObject -{ - NSDictionary *obj = @{@"foo" : @"bar"}; - NSString *json = @"{\"foo\":\"bar\"}"; - XCTAssertEqualObjects(json, RCTJSONStringify(obj, NULL)); -} - -- (void)testEncodingArray -{ - NSArray *array = @[ @"foo", @"bar" ]; - NSString *json = @"[\"foo\",\"bar\"]"; - XCTAssertEqualObjects(json, RCTJSONStringify(array, NULL)); -} - -- (void)testEncodingString -{ - NSString *text = @"Hello\nWorld"; - NSString *json = @"\"Hello\\nWorld\""; - XCTAssertEqualObjects(json, RCTJSONStringify(text, NULL)); -} - -- (void)testEncodingNSError -{ - NSError *underlyingError = [NSError errorWithDomain:@"underlyingDomain" code:421 userInfo:nil]; - NSError *err = [NSError errorWithDomain:@"domain" code:68 userInfo:@{@"NSUnderlyingError" : underlyingError}]; - - // An assertion on the full object would be too brittle since it contains an iOS stack trace - // so we are relying on the behavior of RCTJSONParse, which is tested below. - NSDictionary *jsonObject = RCTJSErrorFromNSError(err); - NSString *jsonString = RCTJSONStringify(jsonObject, NULL); - NSDictionary *json = RCTJSONParse(jsonString, NULL); - XCTAssertEqualObjects(json[@"code"], @"EDOMAIN68"); - XCTAssertEqualObjects(json[@"message"], @"The operation couldn\u2019t be completed. (domain error 68.)"); - XCTAssertEqualObjects(json[@"domain"], @"domain"); - XCTAssertEqualObjects(json[@"userInfo"][@"NSUnderlyingError"][@"code"], @"421"); - XCTAssertEqualObjects(json[@"userInfo"][@"NSUnderlyingError"][@"message"], @"underlying error"); - XCTAssertEqualObjects(json[@"userInfo"][@"NSUnderlyingError"][@"domain"], @"underlyingDomain"); -} - -- (void)testDecodingObject -{ - NSDictionary *obj = @{@"foo" : @"bar"}; - NSString *json = @"{\"foo\":\"bar\"}"; - XCTAssertEqualObjects(obj, RCTJSONParse(json, NULL)); -} - -- (void)testDecodingArray -{ - NSArray *array = @[ @"foo", @"bar" ]; - NSString *json = @"[\"foo\",\"bar\"]"; - XCTAssertEqualObjects(array, RCTJSONParse(json, NULL)); -} - -- (void)testDecodingString -{ - NSString *text = @"Hello\nWorld"; - NSString *json = @"\"Hello\\nWorld\""; - XCTAssertEqualObjects(text, RCTJSONParse(json, NULL)); -} - -- (void)testDecodingMutableArray -{ - NSString *json = @"[1,2,3]"; - NSMutableArray *array = RCTJSONParseMutable(json, NULL); - XCTAssertNoThrow([array addObject:@4]); - XCTAssertEqualObjects(array, (@[ @1, @2, @3, @4 ])); -} - -- (void)testLeadingWhitespace -{ - NSDictionary *obj = @{@"foo" : @"bar"}; - NSString *json = @" \r\n\t{\"foo\":\"bar\"}"; - XCTAssertEqualObjects(obj, RCTJSONParse(json, NULL)); -} - -- (void)testNotJSONSerializable -{ - NSDictionary *obj = @{@"foo" : [NSDate date]}; - NSString *json = @"{\"foo\":null}"; - XCTAssertEqualObjects(json, RCTJSONStringify(obj, NULL)); -} - -- (void)testNaN -{ - NSDictionary *obj = @{@"foo" : @(NAN)}; - NSString *json = @"{\"foo\":0}"; - XCTAssertEqualObjects(json, RCTJSONStringify(obj, NULL)); -} - -- (void)testNotUTF8Convertible -{ - // see https://gist.github.com/0xced/56035d2f57254cf518b5 - NSString *string = [[NSString alloc] initWithBytes:"\xd8\x00" length:2 encoding:NSUTF16StringEncoding]; - NSDictionary *obj = @{@"foo" : string}; - NSString *json = @"{\"foo\":null}"; - XCTAssertEqualObjects(json, RCTJSONStringify(obj, NULL)); -} - -- (void)testErrorPointer -{ - NSDictionary *obj = @{@"foo" : [NSDate date]}; - NSError *error; - XCTAssertNil(RCTJSONStringify(obj, &error)); - XCTAssertNotNil(error); -} - -@end diff --git a/packages/rn-tester/RNTesterUnitTests/RCTMethodArgumentTests.m b/packages/rn-tester/RNTesterUnitTests/RCTMethodArgumentTests.m deleted file mode 100644 index f1682d27b04138..00000000000000 --- a/packages/rn-tester/RNTesterUnitTests/RCTMethodArgumentTests.m +++ /dev/null @@ -1,188 +0,0 @@ -/* - * 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 -#import - -#import - -@interface RCTMethodArgumentTests : XCTestCase - -@end - -@implementation RCTMethodArgumentTests - -extern NSString *RCTParseMethodSignature(const char *methodSignature, NSArray **argTypes); - -- (void)testOneArgument -{ - NSArray *arguments; - const char *methodSignature = "foo:(NSInteger)foo"; - NSString *selector = RCTParseMethodSignature(methodSignature, &arguments); - XCTAssertEqualObjects(selector, @"foo:"); - XCTAssertEqual(arguments.count, (NSUInteger)1); - XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSInteger"); -} - -- (void)testTwoArguments -{ - NSArray *arguments; - const char *methodSignature = "foo:(NSInteger)foo bar:(BOOL)bar"; - NSString *selector = RCTParseMethodSignature(methodSignature, &arguments); - XCTAssertEqualObjects(selector, @"foo:bar:"); - XCTAssertEqual(arguments.count, (NSUInteger)2); - XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSInteger"); - XCTAssertEqualObjects(((RCTMethodArgument *)arguments[1]).type, @"BOOL"); -} - -- (void)testSpaces -{ - NSArray *arguments; - const char *methodSignature = "foo : (NSInteger)foo bar : (BOOL) bar"; - NSString *selector = RCTParseMethodSignature(methodSignature, &arguments); - XCTAssertEqualObjects(selector, @"foo:bar:"); - XCTAssertEqual(arguments.count, (NSUInteger)2); - XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSInteger"); - XCTAssertEqualObjects(((RCTMethodArgument *)arguments[1]).type, @"BOOL"); -} - -- (void)testNewlines -{ - NSArray *arguments; - const char *methodSignature = "foo : (NSInteger)foo\nbar : (BOOL) bar"; - NSString *selector = RCTParseMethodSignature(methodSignature, &arguments); - XCTAssertEqualObjects(selector, @"foo:bar:"); - XCTAssertEqual(arguments.count, (NSUInteger)2); - XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSInteger"); - XCTAssertEqualObjects(((RCTMethodArgument *)arguments[1]).type, @"BOOL"); -} - -- (void)testUnnamedArgs -{ - NSArray *arguments; - const char *methodSignature = "foo:(NSInteger)foo:(BOOL)bar"; - NSString *selector = RCTParseMethodSignature(methodSignature, &arguments); - XCTAssertEqualObjects(selector, @"foo::"); - XCTAssertEqual(arguments.count, (NSUInteger)2); - XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSInteger"); - XCTAssertEqualObjects(((RCTMethodArgument *)arguments[1]).type, @"BOOL"); -} - -- (void)testUntypedUnnamedArgs -{ - NSArray *arguments; - const char *methodSignature = "foo:foo:bar:bar"; - NSString *selector = RCTParseMethodSignature(methodSignature, &arguments); - XCTAssertEqualObjects(selector, @"foo:::"); - XCTAssertEqual(arguments.count, (NSUInteger)3); - XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"id"); - XCTAssertEqualObjects(((RCTMethodArgument *)arguments[1]).type, @"id"); - XCTAssertEqualObjects(((RCTMethodArgument *)arguments[2]).type, @"id"); -} - -- (void)testNamespacedCxxStruct -{ - NSArray *arguments; - const char *methodSignature = "foo:(foo::type &)foo bar:(bar::type &)bar"; - NSString *selector = RCTParseMethodSignature(methodSignature, &arguments); - XCTAssertEqualObjects(selector, @"foo:bar:"); - XCTAssertEqual(arguments.count, (NSUInteger)2); - XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"foo::type"); - XCTAssertEqualObjects(((RCTMethodArgument *)arguments[1]).type, @"bar::type"); -} - -- (void)testAttributes -{ - NSArray *arguments; - const char *methodSignature = "foo:(__attribute__((unused)) NSString *)foo bar:(__unused BOOL)bar"; - NSString *selector = RCTParseMethodSignature(methodSignature, &arguments); - XCTAssertEqualObjects(selector, @"foo:bar:"); - XCTAssertEqual(arguments.count, (NSUInteger)2); - XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSString"); - XCTAssertEqualObjects(((RCTMethodArgument *)arguments[1]).type, @"BOOL"); -} - -- (void)testNullability -{ - NSArray *arguments; - const char *methodSignature = "foo:(nullable NSString *)foo bar:(nonnull NSNumber *)bar baz:(id)baz"; - NSString *selector = RCTParseMethodSignature(methodSignature, &arguments); - XCTAssertEqualObjects(selector, @"foo:bar:baz:"); - XCTAssertEqual(arguments.count, (NSUInteger)3); - XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSString"); - XCTAssertEqualObjects(((RCTMethodArgument *)arguments[1]).type, @"NSNumber"); - XCTAssertEqualObjects(((RCTMethodArgument *)arguments[2]).type, @"id"); - XCTAssertEqual(((RCTMethodArgument *)arguments[0]).nullability, RCTNullable); - XCTAssertEqual(((RCTMethodArgument *)arguments[1]).nullability, RCTNonnullable); - XCTAssertEqual(((RCTMethodArgument *)arguments[2]).nullability, RCTNullabilityUnspecified); -} - -- (void)testSemicolonStripping -{ - NSArray *arguments; - const char *methodSignature = "foo:(NSString *)foo bar:(BOOL)bar;"; - NSString *selector = RCTParseMethodSignature(methodSignature, &arguments); - XCTAssertEqualObjects(selector, @"foo:bar:"); - XCTAssertEqual(arguments.count, (NSUInteger)2); - XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSString"); - XCTAssertEqualObjects(((RCTMethodArgument *)arguments[1]).type, @"BOOL"); -} - -- (void)testUnused -{ - NSArray *arguments; - const char *methodSignature = "foo:(__unused NSString *)foo bar:(NSNumber *)bar"; - NSString *selector = RCTParseMethodSignature(methodSignature, &arguments); - XCTAssertEqualObjects(selector, @"foo:bar:"); - XCTAssertEqual(arguments.count, (NSUInteger)2); - XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSString"); - XCTAssertEqualObjects(((RCTMethodArgument *)arguments[1]).type, @"NSNumber"); - XCTAssertTrue(((RCTMethodArgument *)arguments[0]).unused); - XCTAssertFalse(((RCTMethodArgument *)arguments[1]).unused); -} - -- (void)testGenericArray -{ - NSArray *arguments; - const char *methodSignature = "foo:(NSArray *)foo;"; - NSString *selector = RCTParseMethodSignature(methodSignature, &arguments); - XCTAssertEqualObjects(selector, @"foo:"); - XCTAssertEqual(arguments.count, (NSUInteger)1); - XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSStringArray"); -} - -- (void)testNestedGenericArray -{ - NSArray *arguments; - const char *methodSignature = "foo:(NSArray *> *)foo;"; - NSString *selector = RCTParseMethodSignature(methodSignature, &arguments); - XCTAssertEqualObjects(selector, @"foo:"); - XCTAssertEqual(arguments.count, (NSUInteger)1); - XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSStringArrayArray"); -} - -- (void)testGenericSet -{ - NSArray *arguments; - const char *methodSignature = "foo:(NSSet *)foo;"; - NSString *selector = RCTParseMethodSignature(methodSignature, &arguments); - XCTAssertEqualObjects(selector, @"foo:"); - XCTAssertEqual(arguments.count, (NSUInteger)1); - XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSNumberSet"); -} - -- (void)testGenericDictionary -{ - NSArray *arguments; - const char *methodSignature = "foo:(NSDictionary *)foo;"; - NSString *selector = RCTParseMethodSignature(methodSignature, &arguments); - XCTAssertEqualObjects(selector, @"foo:"); - XCTAssertEqual(arguments.count, (NSUInteger)1); - XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSNumberDictionary"); -} - -@end diff --git a/packages/rn-tester/RNTesterUnitTests/RCTModuleInitNotificationRaceTests.m b/packages/rn-tester/RNTesterUnitTests/RCTModuleInitNotificationRaceTests.m deleted file mode 100644 index 3e472514b532f2..00000000000000 --- a/packages/rn-tester/RNTesterUnitTests/RCTModuleInitNotificationRaceTests.m +++ /dev/null @@ -1,114 +0,0 @@ -/* - * 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 -#import - -#import - -#import -#import -#import -#import -#import -#import - -@interface RCTTestViewManager : RCTViewManager -@end - -@implementation RCTTestViewManager - -RCT_EXPORT_MODULE() - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-implementations" - -- (NSArray *)customBubblingEventTypes -{ - return @[ @"foo" ]; -} - -#pragma clang diagnostic pop - -@end - -@interface RCTNotificationObserverModule : NSObject - -@property (nonatomic, assign) BOOL didDetectViewManagerInit; - -@end - -@implementation RCTNotificationObserverModule - -@synthesize bridge = _bridge; - -RCT_EXPORT_MODULE() - -- (void)initialize -{ - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(didInitViewManager:) - name:RCTDidInitializeModuleNotification - object:nil]; -} - -- (void)didInitViewManager:(NSNotification *)note -{ - id module = note.userInfo[@"module"]; - if ([module isKindOfClass:[RCTTestViewManager class]]) { - _didDetectViewManagerInit = YES; - } -} - -@end - -@interface RCTModuleInitNotificationRaceTests : XCTestCase { - RCTBridge *_bridge; - RCTNotificationObserverModule *_notificationObserver; -} -@end - -@implementation RCTModuleInitNotificationRaceTests - -- (NSURL *)sourceURLForBridge:(__unused RCTBridge *)bridge -{ - NSBundle *bundle = [NSBundle bundleForClass:[self class]]; - return [bundle URLForResource:@"RNTesterUnitTestsBundle" withExtension:@"js"]; -} - -- (NSArray *)extraModulesForBridge:(__unused RCTBridge *)bridge -{ - return @[ [RCTTestViewManager new], _notificationObserver ]; -} - -- (void)setUp -{ - [super setUp]; - - _notificationObserver = [RCTNotificationObserverModule new]; - _bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:nil]; - - dispatch_async(dispatch_get_main_queue(), ^{ - [[self->_bridge uiManager] constantsToExport]; - }); -} - -- (void)tearDown -{ - [super tearDown]; - - _notificationObserver = nil; - [_bridge invalidate]; - _bridge = nil; -} - -- (void)testViewManagerNotInitializedBeforeSetBridgeModule -{ - RCT_RUN_RUNLOOP_WHILE(!_notificationObserver.didDetectViewManagerInit); -} - -@end diff --git a/packages/rn-tester/RNTesterUnitTests/RCTModuleInitTests.m b/packages/rn-tester/RNTesterUnitTests/RCTModuleInitTests.m deleted file mode 100644 index 5b410c221a9b16..00000000000000 --- a/packages/rn-tester/RNTesterUnitTests/RCTModuleInitTests.m +++ /dev/null @@ -1,250 +0,0 @@ -/* - * 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 -#import - -#import -#import -#import -#import -#import -#import -#import - -@interface RCTTestInjectedModule : NSObject -@end - -@implementation RCTTestInjectedModule - -@synthesize bridge = _bridge; -@synthesize methodQueue = _methodQueue; - -RCT_EXPORT_MODULE() - -@end - -@interface RCTTestCustomInitModule : NSObject - -@property (nonatomic, assign) BOOL initializedOnMainQueue; - -@end - -@implementation RCTTestCustomInitModule - -@synthesize bridge = _bridge; -@synthesize methodQueue = _methodQueue; - -RCT_EXPORT_MODULE() - -- (id)init -{ - if ((self = [super init])) { - _initializedOnMainQueue = RCTIsMainQueue(); - } - return self; -} - -@end - -@interface RCTTestCustomSetBridgeModule : NSObject - -@property (nonatomic, assign) BOOL setBridgeOnMainQueue; - -@end - -@implementation RCTTestCustomSetBridgeModule - -@synthesize bridge = _bridge; -@synthesize methodQueue = _methodQueue; - -RCT_EXPORT_MODULE() - -- (void)initialize -{ - _setBridgeOnMainQueue = RCTIsMainQueue(); -} - -@end - -@interface RCTTestExportConstantsModule : NSObject - -@property (nonatomic, assign) BOOL exportedConstants; -@property (nonatomic, assign) BOOL exportedConstantsOnMainQueue; - -@end - -@implementation RCTTestExportConstantsModule - -@synthesize bridge = _bridge; -@synthesize methodQueue = _methodQueue; - -RCT_EXPORT_MODULE() - -- (NSDictionary *)constantsToExport -{ - return [self getConstants]; -} - -- (NSDictionary *)getConstants -{ - _exportedConstants = YES; - _exportedConstantsOnMainQueue = RCTIsMainQueue(); - return @{@"foo" : @"bar"}; -} - -@end - -@interface RCTLazyInitModule : NSObject -@end - -@implementation RCTLazyInitModule - -@synthesize bridge = _bridge; -@synthesize methodQueue = _methodQueue; - -RCT_EXPORT_MODULE() - -@end - -@interface RCTModuleInitTests : XCTestCase { - RCTBridge *_bridge; - BOOL _injectedModuleInitNotificationSent; - BOOL _customInitModuleNotificationSent; - BOOL _customSetBridgeModuleNotificationSent; - BOOL _exportConstantsModuleNotificationSent; - BOOL _lazyInitModuleNotificationSent; - BOOL _lazyInitModuleNotificationSentOnMainQueue; - BOOL _viewManagerModuleNotificationSent; - RCTTestInjectedModule *_injectedModule; -} -@end - -@implementation RCTModuleInitTests - -- (NSURL *)sourceURLForBridge:(__unused RCTBridge *)bridge -{ - NSBundle *bundle = [NSBundle bundleForClass:[self class]]; - return [bundle URLForResource:@"RNTesterUnitTestsBundle" withExtension:@"js"]; -} - -- (NSArray *)extraModulesForBridge:(__unused RCTBridge *)bridge -{ - return @[ _injectedModule ]; -} - -- (void)setUp -{ - [super setUp]; - - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(moduleDidInit:) - name:RCTDidInitializeModuleNotification - object:nil]; - - _injectedModuleInitNotificationSent = NO; - _customInitModuleNotificationSent = NO; - _customSetBridgeModuleNotificationSent = NO; - _exportConstantsModuleNotificationSent = NO; - _lazyInitModuleNotificationSent = NO; - _viewManagerModuleNotificationSent = NO; - _injectedModule = [RCTTestInjectedModule new]; - _bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:nil]; -} - -- (void)tearDown -{ - [super tearDown]; - - [[NSNotificationCenter defaultCenter] removeObserver:self name:RCTDidInitializeModuleNotification object:nil]; - - [_bridge invalidate]; - _bridge = nil; -} - -- (void)moduleDidInit:(NSNotification *)note -{ - id module = note.userInfo[@"module"]; - if ([module isKindOfClass:[RCTTestInjectedModule class]]) { - _injectedModuleInitNotificationSent = YES; - } else if ([module isKindOfClass:[RCTTestCustomInitModule class]]) { - _customInitModuleNotificationSent = YES; - } else if ([module isKindOfClass:[RCTTestCustomSetBridgeModule class]]) { - _customSetBridgeModuleNotificationSent = YES; - } else if ([module isKindOfClass:[RCTTestExportConstantsModule class]]) { - _exportConstantsModuleNotificationSent = YES; - } else if ([module isKindOfClass:[RCTLazyInitModule class]]) { - _lazyInitModuleNotificationSent = YES; - _lazyInitModuleNotificationSentOnMainQueue = RCTIsMainQueue(); - } -} - -- (void)testInjectedModulesInitializedDuringBridgeInit -{ - XCTAssertEqual(_injectedModule, [_bridge moduleForClass:[RCTTestInjectedModule class]]); - XCTAssertEqual(_injectedModule.bridge, _bridge.batchedBridge); - XCTAssertNotNil(_injectedModule.methodQueue); - RCT_RUN_RUNLOOP_WHILE(!_injectedModuleInitNotificationSent); - XCTAssertTrue(_injectedModuleInitNotificationSent); -} - -- (void)testCustomInitModuleInitializedAtBridgeStartup -{ - RCT_RUN_RUNLOOP_WHILE(!_customInitModuleNotificationSent); - XCTAssertTrue(_customInitModuleNotificationSent); - RCTTestCustomInitModule *module = [_bridge moduleForClass:[RCTTestCustomInitModule class]]; - XCTAssertTrue(module.initializedOnMainQueue); - XCTAssertEqual(module.bridge, _bridge.batchedBridge); - XCTAssertNotNil(module.methodQueue); -} - -- (void)testCustomSetBridgeModuleInitializedAtBridgeStartup -{ - XCTAssertFalse(_customSetBridgeModuleNotificationSent); - - __block RCTTestCustomSetBridgeModule *module; - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - module = [self->_bridge moduleForClass: [RCTTestCustomSetBridgeModule class]]; - }); - - RCT_RUN_RUNLOOP_WHILE(!module); - XCTAssertTrue(_customSetBridgeModuleNotificationSent); - XCTAssertFalse(module.setBridgeOnMainQueue); - XCTAssertEqual(module.bridge, _bridge.batchedBridge); - XCTAssertNotNil(module.methodQueue); -} - -- (void)testExportConstantsModuleInitializedAtBridgeStartup -{ - RCT_RUN_RUNLOOP_WHILE(!_exportConstantsModuleNotificationSent); - XCTAssertTrue(_exportConstantsModuleNotificationSent); - RCTTestExportConstantsModule *module = [_bridge moduleForClass:[RCTTestExportConstantsModule class]]; - RCT_RUN_RUNLOOP_WHILE(!module.exportedConstants); - XCTAssertTrue(module.exportedConstants); - XCTAssertTrue(module.exportedConstantsOnMainQueue); - XCTAssertEqual(module.bridge, _bridge.batchedBridge); - XCTAssertNotNil(module.methodQueue); -} - -- (void)testLazyInitModuleNotInitializedDuringBridgeInit -{ - XCTAssertFalse(_lazyInitModuleNotificationSent); - - __block RCTLazyInitModule *module; - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - module = [self->_bridge moduleForClass: [RCTLazyInitModule class]]; - }); - - RCT_RUN_RUNLOOP_WHILE(!module); - XCTAssertTrue(_lazyInitModuleNotificationSent); - XCTAssertFalse(_lazyInitModuleNotificationSentOnMainQueue); - XCTAssertNotNil(module); - XCTAssertEqual(module.bridge, _bridge.batchedBridge); - XCTAssertNotNil(module.methodQueue); -} - -@end diff --git a/packages/rn-tester/RNTesterUnitTests/RCTModuleMethodTests.mm b/packages/rn-tester/RNTesterUnitTests/RCTModuleMethodTests.mm deleted file mode 100644 index 0f5c4312fc1cba..00000000000000 --- a/packages/rn-tester/RNTesterUnitTests/RCTModuleMethodTests.mm +++ /dev/null @@ -1,294 +0,0 @@ -/* - * 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 -#import - -#import -#import -#import - -static BOOL RCTLogsError(void (^block)(void)) -{ - __block BOOL loggedError = NO; - RCTPerformBlockWithLogFunction( - block, - ^(RCTLogLevel level, - __unused RCTLogSource source, - __unused NSString *fileName, - __unused NSNumber *lineNumber, - __unused NSString *message) { - loggedError = (level == RCTLogLevelError); - }); - return loggedError; -} - -@interface RCTModuleMethodTests : XCTestCase - -@end - -@implementation RCTModuleMethodTests { - CGRect _s; -} - -static RCTModuleMethod *buildDefaultMethodWithMethodSignature(const char *methodSignature) -{ - // This leaks a RCTMethodInfo, but it's a test, so... - RCTMethodInfo *methodInfo = new RCTMethodInfo{.objcName = methodSignature, .isSync = NO}; - return [[RCTModuleMethod alloc] initWithExportedMethod:methodInfo moduleClass:[RCTModuleMethodTests class]]; -} - -static RCTModuleMethod *buildSyncMethodWithMethodSignature(const char *methodSignature) -{ - // This leaks a RCTMethodInfo, but it's a test, so... - RCTMethodInfo *methodInfo = new RCTMethodInfo{.objcName = methodSignature, .isSync = YES}; - return [[RCTModuleMethod alloc] initWithExportedMethod:methodInfo moduleClass:[RCTModuleMethodTests class]]; -} - -+ (NSString *)moduleName -{ - return nil; -} - -- (void)doFoo -{ -} - -- (void)doFooWithBar:(__unused NSString *)bar -{ -} - -- (id)echoString:(NSString *)input -{ - return input; -} -- (id)methodThatReturnsNil -{ - return nil; -} -- (void)openURL:(NSURL *)URL resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject -{ -} -- (void)openURL:(NSURL *)URL callback:(RCTResponseSenderBlock)callback -{ -} -- (id)methodThatCallsCallbackWithArg:(NSString *)input callback:(RCTResponseSenderBlock)callback -{ - callback(@[ input ]); - return nil; -} - -- (void)testNonnull -{ - const char *methodSignature = "doFooWithBar:(nonnull NSString *)bar"; - RCTModuleMethod *method = buildDefaultMethodWithMethodSignature(methodSignature); - XCTAssertFalse(RCTLogsError(^{ - [method invokeWithBridge:nil module:self arguments:@[ @"Hello World" ]]; - })); - - XCTAssertTrue(RCTLogsError(^{ - [method invokeWithBridge:nil module:self arguments:@[ [NSNull null] ]]; - })); -} - -- (void)doFooWithNumber:(__unused NSNumber *)n -{ -} -- (void)doFooWithDouble:(__unused double)n -{ -} -- (void)doFooWithInteger:(__unused NSInteger)n -{ -} -- (void)doFooWithCGRect:(CGRect)s -{ - _s = s; -} - -- (void)doFoo:(__unused NSString *)foo -{ -} - -- (void)testNumbersNonnull -{ - { - // Specifying an NSNumber param without nonnull isn't allowed - XCTAssertTrue(RCTLogsError(^{ - const char *methodSignature = "doFooWithNumber:(NSNumber *)n"; - RCTModuleMethod *method = buildDefaultMethodWithMethodSignature(methodSignature); - // Invoke method to trigger parsing - [method invokeWithBridge:nil module:self arguments:@[ @1 ]]; - })); - } - - { - const char *methodSignature = "doFooWithNumber:(nonnull NSNumber *)n"; - RCTModuleMethod *method = buildDefaultMethodWithMethodSignature(methodSignature); - XCTAssertTrue(RCTLogsError(^{ - [method invokeWithBridge:nil module:self arguments:@[ [NSNull null] ]]; - })); - } - - { - const char *methodSignature = "doFooWithDouble:(double)n"; - RCTModuleMethod *method = buildDefaultMethodWithMethodSignature(methodSignature); - XCTAssertTrue(RCTLogsError(^{ - [method invokeWithBridge:nil module:self arguments:@[ [NSNull null] ]]; - })); - } - - { - const char *methodSignature = "doFooWithInteger:(NSInteger)n"; - RCTModuleMethod *method = buildDefaultMethodWithMethodSignature(methodSignature); - XCTAssertTrue(RCTLogsError(^{ - [method invokeWithBridge:nil module:self arguments:@[ [NSNull null] ]]; - })); - } -} - -- (void)testStructArgument -{ - const char *methodSignature = "doFooWithCGRect:(CGRect)s"; - RCTModuleMethod *method = buildDefaultMethodWithMethodSignature(methodSignature); - - CGRect r = CGRectMake(10, 20, 30, 40); - [method invokeWithBridge:nil module:self arguments:@[ @[ @10, @20, @30, @40 ] ]]; - XCTAssertTrue(CGRectEqualToRect(r, _s)); -} - -- (void)testWhitespaceTolerance -{ - const char *methodSignature = "doFoo : \t (NSString *)foo"; - - __block RCTModuleMethod *method; - XCTAssertFalse(RCTLogsError(^{ - method = buildDefaultMethodWithMethodSignature(methodSignature); - })); - - XCTAssertEqualObjects(@(method.JSMethodName), @"doFoo"); - - XCTAssertFalse(RCTLogsError(^{ - [method invokeWithBridge:nil module:self arguments:@[ @"bar" ]]; - })); -} - -- (void)testFunctionType -{ - { - const char *methodSignature = "doFoo"; - RCTModuleMethod *method = buildDefaultMethodWithMethodSignature(methodSignature); - XCTAssertTrue(method.functionType == RCTFunctionTypeNormal); - XCTAssertFalse( - RCTLogsError(^{ - // Invoke method to trigger parsing - __unused SEL selector = method.selector; - }), - @"Unexpected error when parsing normal function"); - } - - { - const char *methodSignature = "openURL:(NSURL *)URL callback:(RCTResponseSenderBlock)callBack"; - RCTModuleMethod *method = buildDefaultMethodWithMethodSignature(methodSignature); - XCTAssertTrue(method.functionType == RCTFunctionTypeNormal); - XCTAssertFalse( - RCTLogsError(^{ - // Invoke method to trigger parsing - __unused SEL selector = method.selector; - }), - @"Unexpected error when parsing normal function with callback"); - } - - { - const char *methodSignature = - "openURL:(NSURL *)URL resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject"; - RCTModuleMethod *method = buildDefaultMethodWithMethodSignature(methodSignature); - XCTAssertTrue(method.functionType == RCTFunctionTypePromise); - XCTAssertFalse( - RCTLogsError(^{ - // Invoke method to trigger parsing - __unused SEL selector = method.selector; - }), - @"Unexpected error when parsing promise function"); - } - - { - const char *methodSignature = "echoString:(NSString *)input"; - RCTModuleMethod *method = buildSyncMethodWithMethodSignature(methodSignature); - XCTAssertTrue(method.functionType == RCTFunctionTypeSync); - XCTAssertFalse( - RCTLogsError(^{ - // Invoke method to trigger parsing - __unused SEL selector = method.selector; - }), - @"Unexpected error when parsing sync function"); - } - - { - const char *methodSignature = - "methodThatCallsCallbackWithArg:(NSString *)input callback:(RCTResponseSenderBlock)callback"; - RCTModuleMethod *method = buildSyncMethodWithMethodSignature(methodSignature); - XCTAssertTrue(method.functionType == RCTFunctionTypeSync); - XCTAssertFalse( - RCTLogsError(^{ - // Invoke method to trigger parsing - __unused SEL selector = method.selector; - }), - @"Unexpected error when parsing sync function with callback"); - } -} - -- (void)testReturnsValueForSyncFunction -{ - { - const char *methodSignature = "echoString:(NSString *)input"; - RCTModuleMethod *method = buildSyncMethodWithMethodSignature(methodSignature); - id result = [method invokeWithBridge:nil module:self arguments:@[ @"Test String Value" ]]; - XCTAssertEqualObjects(result, @"Test String Value"); - } - - { - const char *methodSignature = "methodThatReturnsNil"; - RCTModuleMethod *method = buildSyncMethodWithMethodSignature(methodSignature); - id result = [method invokeWithBridge:nil module:self arguments:@[]]; - XCTAssertNil(result); - } -} - -- (void)testReturnsNilForDefaultFunction -{ - const char *methodSignature = "doFoo"; - RCTModuleMethod *method = buildDefaultMethodWithMethodSignature(methodSignature); - id result = [method invokeWithBridge:nil module:self arguments:@[]]; - XCTAssertNil(result); -} - -- (void)testReturnTypeForSyncFunction -{ - { - const char *methodSignature = "methodThatReturnsNil"; - RCTModuleMethod *method = buildSyncMethodWithMethodSignature(methodSignature); - XCTAssertFalse( - RCTLogsError(^{ - // Invoke method to trigger parsing - __unused SEL selector = method.selector; - }), - @"Unexpected error when parsing sync function with (id) return type"); - } - - { - const char *methodSignature = "doFoo"; - RCTModuleMethod *method = buildSyncMethodWithMethodSignature(methodSignature); - XCTAssertTrue( - RCTLogsError(^{ - // Invoke method to trigger parsing - __unused SEL selector = method.selector; - }), - @"Failed to trigger an error when parsing sync function with non-(id) return type"); - } -} - -@end diff --git a/packages/rn-tester/RNTesterUnitTests/RCTMultipartStreamReaderTests.m b/packages/rn-tester/RNTesterUnitTests/RCTMultipartStreamReaderTests.m deleted file mode 100644 index 4e711d03f56ea2..00000000000000 --- a/packages/rn-tester/RNTesterUnitTests/RCTMultipartStreamReaderTests.m +++ /dev/null @@ -1,118 +0,0 @@ -/* - * 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 - -#import - -@interface RCTMultipartStreamReaderTests : XCTestCase - -@end - -@implementation RCTMultipartStreamReaderTests - -- (void)testSimpleCase -{ - NSString *response = - @"preamble, should be ignored\r\n" - @"--sample_boundary\r\n" - @"Content-Type: application/json; charset=utf-8\r\n" - @"Content-Length: 2\r\n\r\n" - @"{}\r\n" - @"--sample_boundary--\r\n" - @"epilogue, should be ignored"; - - NSInputStream *inputStream = [NSInputStream inputStreamWithData:[response dataUsingEncoding:NSUTF8StringEncoding]]; - RCTMultipartStreamReader *reader = [[RCTMultipartStreamReader alloc] initWithInputStream:inputStream - boundary:@"sample_boundary"]; - __block NSInteger count = 0; - BOOL success = [reader - readAllPartsWithCompletionCallback:^(NSDictionary *headers, NSData *content, BOOL done) { - XCTAssertTrue(done); - XCTAssertEqualObjects(headers[@"Content-Type"], @"application/json; charset=utf-8"); - XCTAssertEqualObjects([[NSString alloc] initWithData:content encoding:NSUTF8StringEncoding], @"{}"); - count++; - } - progressCallback:nil]; - XCTAssertTrue(success); - XCTAssertEqual(count, 1); -} - -- (void)testMultipleParts -{ - NSString *response = - @"preamble, should be ignored\r\n" - @"--sample_boundary\r\n" - @"1\r\n" - @"--sample_boundary\r\n" - @"2\r\n" - @"--sample_boundary\r\n" - @"3\r\n" - @"--sample_boundary--\r\n" - @"epilogue, should be ignored"; - - NSInputStream *inputStream = [NSInputStream inputStreamWithData:[response dataUsingEncoding:NSUTF8StringEncoding]]; - RCTMultipartStreamReader *reader = [[RCTMultipartStreamReader alloc] initWithInputStream:inputStream - boundary:@"sample_boundary"]; - __block NSInteger count = 0; - BOOL success = [reader - readAllPartsWithCompletionCallback:^(__unused NSDictionary *headers, NSData *content, BOOL done) { - count++; - XCTAssertEqual(done, count == 3); - NSString *expectedBody = [NSString stringWithFormat:@"%ld", (long)count]; - NSString *actualBody = [[NSString alloc] initWithData:content encoding:NSUTF8StringEncoding]; - XCTAssertEqualObjects(actualBody, expectedBody); - } - progressCallback:nil]; - XCTAssertTrue(success); - XCTAssertEqual(count, 3); -} - -- (void)testNoDelimiter -{ - NSString *response = @"Yolo"; - - NSInputStream *inputStream = [NSInputStream inputStreamWithData:[response dataUsingEncoding:NSUTF8StringEncoding]]; - RCTMultipartStreamReader *reader = [[RCTMultipartStreamReader alloc] initWithInputStream:inputStream - boundary:@"sample_boundary"]; - __block NSInteger count = 0; - BOOL success = [reader - readAllPartsWithCompletionCallback:^( - __unused NSDictionary *headers, __unused NSData *content, __unused BOOL done) { - count++; - } - progressCallback:nil]; - XCTAssertFalse(success); - XCTAssertEqual(count, 0); -} - -- (void)testNoCloseDelimiter -{ - NSString *response = - @"preamble, should be ignored\r\n" - @"--sample_boundary\r\n" - @"Content-Type: application/json; charset=utf-8\r\n" - @"Content-Length: 2\r\n\r\n" - @"{}\r\n" - @"--sample_boundary\r\n" - @"incomplete message..."; - - NSInputStream *inputStream = [NSInputStream inputStreamWithData:[response dataUsingEncoding:NSUTF8StringEncoding]]; - RCTMultipartStreamReader *reader = [[RCTMultipartStreamReader alloc] initWithInputStream:inputStream - boundary:@"sample_boundary"]; - __block NSInteger count = 0; - BOOL success = [reader - readAllPartsWithCompletionCallback:^( - __unused NSDictionary *headers, __unused NSData *content, __unused BOOL done) { - count++; - } - progressCallback:nil]; - XCTAssertFalse(success); - XCTAssertEqual(count, 1); -} - -@end diff --git a/packages/rn-tester/RNTesterUnitTests/RCTNativeAnimatedNodesManagerTests.m b/packages/rn-tester/RNTesterUnitTests/RCTNativeAnimatedNodesManagerTests.m deleted file mode 100644 index 7e0c3fcefdddf6..00000000000000 --- a/packages/rn-tester/RNTesterUnitTests/RCTNativeAnimatedNodesManagerTests.m +++ /dev/null @@ -1,1080 +0,0 @@ -/* - * 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 - -#import "OCMock/OCMock.h" - -#import -#import -#import - -static const NSTimeInterval FRAME_LENGTH = 1.0 / 60.0; - -@interface RCTFakeDisplayLink : CADisplayLink - -@end - -@implementation RCTFakeDisplayLink { - NSTimeInterval _timestamp; -} - -- (instancetype)init -{ - self = [super init]; - if (self) { - _timestamp = 1124.1234143251; // Random - } - return self; -} - -- (NSTimeInterval)timestamp -{ - _timestamp += FRAME_LENGTH; - return _timestamp; -} - -@end - -@interface RCTFakeValueObserver : NSObject - -@property (nonatomic, strong) NSMutableArray *calls; - -@end - -@implementation RCTFakeValueObserver - -- (instancetype)init -{ - self = [super init]; - if (self) { - _calls = [NSMutableArray new]; - } - return self; -} - -- (void)animatedNode:(__unused RCTValueAnimatedNode *)node didUpdateValue:(CGFloat)value -{ - [_calls addObject:@(value)]; -} - -@end - -@interface RCTFakeEvent : NSObject - -@end - -@implementation RCTFakeEvent { - NSArray *_arguments; -} - -@synthesize eventName = _eventName; -@synthesize viewTag = _viewTag; -@synthesize coalescingKey = _coalescingKey; - -- (instancetype)initWithName:(NSString *)name viewTag:(NSNumber *)viewTag arguments:(NSArray *)arguments -{ - self = [super init]; - if (self) { - _eventName = name; - _viewTag = viewTag; - _arguments = arguments; - } - return self; -} - -- (NSArray *)arguments -{ - return _arguments; -} - -RCT_NOT_IMPLEMENTED(+(NSString *)moduleDotMethod); -RCT_NOT_IMPLEMENTED(-(BOOL)canCoalesce); -RCT_NOT_IMPLEMENTED(-(id)coalesceWithEvent : (id)newEvent); - -@end - -static id RCTPropChecker(NSString *prop, NSNumber *value) -{ - return [OCMArg checkWithBlock:^BOOL(NSDictionary *props) { - BOOL match = fabs(props[prop].doubleValue - value.doubleValue) < FLT_EPSILON; - if (!match) { - NSLog(@"Props `%@` with value `%@` is not close to `%@`", prop, props[prop], value); - } - return match; - }]; -} - -@interface RCTNativeAnimatedNodesManagerTests : XCTestCase - -@end - -@implementation RCTNativeAnimatedNodesManagerTests { - id _uiManager; - RCTNativeAnimatedNodesManager *_nodesManager; - RCTFakeDisplayLink *_displayLink; -} - -- (void)setUp -{ - [super setUp]; - - RCTBridge *bridge = [OCMockObject niceMockForClass:[RCTBridge class]]; - _uiManager = [OCMockObject niceMockForClass:[RCTUIManager class]]; - OCMStub([bridge uiManager]).andReturn(_uiManager); - _nodesManager = [[RCTNativeAnimatedNodesManager alloc] initWithBridge:bridge - surfacePresenter:bridge.surfacePresenter]; - _displayLink = [RCTFakeDisplayLink new]; -} - -/** - * Generates a simple animated nodes graph and attaches the props node to a given viewTag - * Parameter opacity is used as a initial value for the "opacity" attribute. - * - * Nodes are connected as follows (nodes IDs in parens): - * ValueNode(1) -> StyleNode(3) -> PropNode(5) - */ -- (void)createSimpleAnimatedView:(NSNumber *)viewTag withOpacity:(CGFloat)opacity -{ - [_nodesManager createAnimatedNode:@101 config:@{@"type" : @"value", @"value" : @(opacity), @"offset" : @0}]; - [_nodesManager createAnimatedNode:@201 config:@{@"type" : @"style", @"style" : @{@"opacity" : @101}}]; - [_nodesManager createAnimatedNode:@301 config:@{@"type" : @"props", @"props" : @{@"style" : @201}}]; - - [_nodesManager connectAnimatedNodes:@101 childTag:@201]; - [_nodesManager connectAnimatedNodes:@201 childTag:@301]; - [_nodesManager connectAnimatedNodeToView:@301 viewTag:viewTag viewName:@"UIView"]; -} - -- (void)testFramesAnimation -{ - [self createSimpleAnimatedView:@1001 withOpacity:0]; - NSArray *frames = @[ @0, @0.2, @0.4, @0.6, @0.8, @1 ]; - [_nodesManager startAnimatingNode:@1 - nodeTag:@101 - config:@{@"type" : @"frames", @"frames" : frames, @"toValue" : @1} - endCallback:nil]; - - for (NSNumber *frame in frames) { - [[_uiManager expect] synchronouslyUpdateViewOnUIThread:@1001 - viewName:@"UIView" - props:RCTPropChecker(@"opacity", frame)]; - [_nodesManager stepAnimations:_displayLink]; - [_uiManager verify]; - } - - [[_uiManager expect] synchronouslyUpdateViewOnUIThread:@1001 viewName:@"UIView" props:RCTPropChecker(@"opacity", @1)]; - [_nodesManager stepAnimations:_displayLink]; - [_uiManager verify]; - - [[_uiManager reject] synchronouslyUpdateViewOnUIThread:OCMOCK_ANY viewName:OCMOCK_ANY props:OCMOCK_ANY]; - [_nodesManager stepAnimations:_displayLink]; - [_uiManager verify]; -} - -- (void)testFramesAnimationLoop -{ - [self createSimpleAnimatedView:@1001 withOpacity:0]; - NSArray *frames = @[ @0, @0.2, @0.4, @0.6, @0.8, @1 ]; - [_nodesManager startAnimatingNode:@1 - nodeTag:@101 - config:@{@"type" : @"frames", @"frames" : frames, @"toValue" : @1, @"iterations" : @5} - endCallback:nil]; - - for (NSUInteger it = 0; it < 5; it++) { - for (NSNumber *frame in frames) { - [[_uiManager expect] synchronouslyUpdateViewOnUIThread:@1001 - viewName:@"UIView" - props:RCTPropChecker(@"opacity", frame)]; - [_nodesManager stepAnimations:_displayLink]; - [_uiManager verify]; - } - } - - [[_uiManager expect] synchronouslyUpdateViewOnUIThread:@1001 viewName:@"UIView" props:RCTPropChecker(@"opacity", @1)]; - - [_nodesManager stepAnimations:_displayLink]; - [_uiManager verify]; - - [[_uiManager reject] synchronouslyUpdateViewOnUIThread:OCMOCK_ANY viewName:OCMOCK_ANY props:OCMOCK_ANY]; - [_nodesManager stepAnimations:_displayLink]; - [_uiManager verify]; -} - -- (void)testNodeValueListenerIfNotListening -{ - NSNumber *nodeId = @101; - [self createSimpleAnimatedView:@1001 withOpacity:0]; - NSArray *frames = @[ @0, @0.2, @0.4, @0.6, @0.8, @1 ]; - - RCTFakeValueObserver *observer = [RCTFakeValueObserver new]; - [_nodesManager startListeningToAnimatedNodeValue:nodeId valueObserver:observer]; - - [_nodesManager startAnimatingNode:@1 - nodeTag:nodeId - config:@{@"type" : @"frames", @"frames" : frames, @"toValue" : @1} - endCallback:nil]; - - [_nodesManager stepAnimations:_displayLink]; - XCTAssertEqual(observer.calls.count, 1UL); - XCTAssertEqualObjects(observer.calls[0], @0); - - [_nodesManager stopListeningToAnimatedNodeValue:nodeId]; - - [_nodesManager stepAnimations:_displayLink]; - XCTAssertEqual(observer.calls.count, 1UL); -} - -- (void)testNodeValueListenerIfListening -{ - NSNumber *nodeId = @101; - [self createSimpleAnimatedView:@1001 withOpacity:0]; - NSArray *frames = @[ @0, @0.2, @0.4, @0.6, @0.8, @1 ]; - - RCTFakeValueObserver *observer = [RCTFakeValueObserver new]; - [_nodesManager startListeningToAnimatedNodeValue:nodeId valueObserver:observer]; - - [_nodesManager startAnimatingNode:@1 - nodeTag:nodeId - config:@{@"type" : @"frames", @"frames" : frames, @"toValue" : @1} - endCallback:nil]; - - for (NSUInteger i = 0; i < frames.count; i++) { - [_nodesManager stepAnimations:_displayLink]; - XCTAssertEqual(observer.calls.count, i + 1); - XCTAssertEqualWithAccuracy(observer.calls[i].doubleValue, frames[i].doubleValue, FLT_EPSILON); - } - - [_nodesManager stepAnimations:_displayLink]; - XCTAssertEqual(observer.calls.count, 7UL); - XCTAssertEqualObjects(observer.calls[6], @1); - - [_nodesManager stepAnimations:_displayLink]; - XCTAssertEqual(observer.calls.count, 7UL); -} - -- (void)performSpringAnimationTestWithConfig:(NSDictionary *)config isCriticallyDamped:(BOOL)testForCriticallyDamped -{ - [self createSimpleAnimatedView:@1001 withOpacity:0]; - [_nodesManager startAnimatingNode:@1 nodeTag:@101 config:config endCallback:nil]; - - BOOL wasGreaterThanOne = NO; - CGFloat previousValue = 0; - __block CGFloat currentValue; - [[[_uiManager stub] andDo:^(NSInvocation *invocation) { - __unsafe_unretained NSDictionary *props; - [invocation getArgument:&props atIndex:4]; - currentValue = props[@"opacity"].doubleValue; - }] synchronouslyUpdateViewOnUIThread:OCMOCK_ANY viewName:OCMOCK_ANY props:OCMOCK_ANY]; - - // Run for 3 seconds. - for (NSUInteger i = 0; i < 3 * 60; i++) { - [_nodesManager stepAnimations:_displayLink]; - - if (currentValue > 1) { - wasGreaterThanOne = YES; - } - - // Verify that animation step is relatively small. - XCTAssertLessThan(fabs(currentValue - previousValue), 0.12); - - previousValue = currentValue; - } - - // Verify that we've reach the final value at the end of animation. - XCTAssertEqual(previousValue, 1.0); - - // Verify that value has reached some maximum value that is greater than the final value (bounce). - if (testForCriticallyDamped) { - XCTAssertFalse(wasGreaterThanOne); - } else { - XCTAssertTrue(wasGreaterThanOne); - } - - [[_uiManager reject] synchronouslyUpdateViewOnUIThread:OCMOCK_ANY viewName:OCMOCK_ANY props:OCMOCK_ANY]; - [_nodesManager stepAnimations:_displayLink]; - [_uiManager verify]; -} - -- (void)testUnderdampedSpringAnimation -{ - [self performSpringAnimationTestWithConfig:@{ - @"type" : @"spring", - @"stiffness" : @230.3, - @"damping" : @22, - @"mass" : @1, - @"initialVelocity" : @0, - @"toValue" : @1, - @"restSpeedThreshold" : @0.001, - @"restDisplacementThreshold" : @0.001, - @"overshootClamping" : @NO - } - isCriticallyDamped:NO]; -} - -- (void)testCritcallyDampedSpringAnimation -{ - [self performSpringAnimationTestWithConfig:@{ - @"type" : @"spring", - @"stiffness" : @1000, - @"damping" : @500, - @"mass" : @3, - @"initialVelocity" : @0, - @"toValue" : @1, - @"restSpeedThreshold" : @0.001, - @"restDisplacementThreshold" : @0.001, - @"overshootClamping" : @NO - } - isCriticallyDamped:YES]; -} - -- (void)testDecayAnimation -{ - [self createSimpleAnimatedView:@1001 withOpacity:0]; - [_nodesManager startAnimatingNode:@1 - nodeTag:@101 - config:@{@"type" : @"decay", @"velocity" : @0.5, @"deceleration" : @0.998} - endCallback:nil]; - - __block CGFloat previousValue; - __block CGFloat currentValue; - CGFloat previousDiff = CGFLOAT_MAX; - - [_nodesManager stepAnimations:_displayLink]; - - [[[_uiManager stub] andDo:^(NSInvocation *invocation) { - __unsafe_unretained NSDictionary *props; - [invocation getArgument:&props atIndex:4]; - currentValue = props[@"opacity"].doubleValue; - }] synchronouslyUpdateViewOnUIThread:OCMOCK_ANY viewName:OCMOCK_ANY props:OCMOCK_ANY]; - - // Run 3 secs of animation. - for (NSUInteger i = 0; i < 3 * 60; i++) { - [_nodesManager stepAnimations:_displayLink]; - CGFloat currentDiff = currentValue - previousValue; - // Verify monotonicity. - // Greater *or equal* because the animation stops during these 3 seconds. - XCTAssertGreaterThanOrEqual(currentValue, previousValue); - // Verify decay. - XCTAssertLessThanOrEqual(currentDiff, previousDiff); - previousValue = currentValue; - previousDiff = currentDiff; - } - - // Should be done in 3 secs. - [[_uiManager reject] synchronouslyUpdateViewOnUIThread:OCMOCK_ANY viewName:OCMOCK_ANY props:OCMOCK_ANY]; - [_nodesManager stepAnimations:_displayLink]; - [_uiManager verify]; -} - -- (void)testDecayAnimationLoop -{ - [self createSimpleAnimatedView:@1001 withOpacity:0]; - [_nodesManager - startAnimatingNode:@1 - nodeTag:@101 - config:@{@"type" : @"decay", @"velocity" : @0.5, @"deceleration" : @0.998, @"iterations" : @5} - endCallback:nil]; - - __block CGFloat previousValue; - __block CGFloat currentValue; - BOOL didComeToRest = NO; - NSUInteger numberOfResets = 0; - - [[[_uiManager stub] andDo:^(NSInvocation *invocation) { - __unsafe_unretained NSDictionary *props; - [invocation getArgument:&props atIndex:4]; - currentValue = props[@"opacity"].doubleValue; - }] synchronouslyUpdateViewOnUIThread:OCMOCK_ANY viewName:OCMOCK_ANY props:OCMOCK_ANY]; - - // Run 3 secs of animation five times. - for (NSUInteger i = 0; i < 3 * 60 * 5; i++) { - [_nodesManager stepAnimations:_displayLink]; - - // Verify monotonicity when not resetting the animation. - // Greater *or equal* because the animation stops during these 3 seconds. - if (!didComeToRest) { - XCTAssertGreaterThanOrEqual(currentValue, previousValue); - } - - if (didComeToRest && currentValue != previousValue) { - numberOfResets++; - didComeToRest = NO; - } - - // Test if animation has come to rest using the 0.1 threshold from DecayAnimation.m. - didComeToRest = fabs(currentValue - previousValue) < 0.1; - previousValue = currentValue; - } - - // The animation should have reset 4 times. - XCTAssertEqual(numberOfResets, 4u); - - [[_uiManager reject] synchronouslyUpdateViewOnUIThread:OCMOCK_ANY viewName:OCMOCK_ANY props:OCMOCK_ANY]; - [_nodesManager stepAnimations:_displayLink]; - [_uiManager verify]; -} - -- (void)testSpringAnimationLoop -{ - [self createSimpleAnimatedView:@1001 withOpacity:0]; - [_nodesManager startAnimatingNode:@1 - nodeTag:@101 - config:@{ - @"type" : @"spring", - @"iterations" : @5, - @"stiffness" : @230.2, - @"damping" : @22, - @"mass" : @1, - @"initialVelocity" : @0, - @"toValue" : @1, - @"restSpeedThreshold" : @0.001, - @"restDisplacementThreshold" : @0.001, - @"overshootClamping" : @NO - } - endCallback:nil]; - - BOOL didComeToRest = NO; - CGFloat previousValue = 0; - NSUInteger numberOfResets = 0; - __block CGFloat currentValue; - [[[_uiManager stub] andDo:^(NSInvocation *invocation) { - __unsafe_unretained NSDictionary *props; - [invocation getArgument:&props atIndex:4]; - currentValue = props[@"opacity"].doubleValue; - }] synchronouslyUpdateViewOnUIThread:OCMOCK_ANY viewName:OCMOCK_ANY props:OCMOCK_ANY]; - - // Run for 3 seconds five times. - for (NSUInteger i = 0; i < 3 * 60 * 5; i++) { - [_nodesManager stepAnimations:_displayLink]; - - if (!didComeToRest) { - // Verify that animation step is relatively small. - XCTAssertLessThan(fabs(currentValue - previousValue), 0.12); - } - - // Test to see if it reset after coming to rest - if (didComeToRest && currentValue == 0) { - didComeToRest = NO; - numberOfResets++; - } - - // Record that the animation did come to rest when it rests on toValue. - didComeToRest = fabs(currentValue - 1) < 0.001 && fabs(currentValue - previousValue) < 0.001; - - previousValue = currentValue; - } - - // Verify that value reset 4 times after finishing a full animation and is currently resting. - XCTAssertEqual(numberOfResets, 4u); - XCTAssertTrue(didComeToRest); - - [[_uiManager reject] synchronouslyUpdateViewOnUIThread:OCMOCK_ANY viewName:OCMOCK_ANY props:OCMOCK_ANY]; - [_nodesManager stepAnimations:_displayLink]; - [_uiManager verify]; -} - -- (void)testAnimationCallbackFinish -{ - [self createSimpleAnimatedView:@1001 withOpacity:0]; - NSArray *frames = @[ @0, @1 ]; - - __block NSInteger endCallbackCalls = 0; - - RCTResponseSenderBlock endCallback = ^(NSArray *response) { - endCallbackCalls++; - NSArray *expected = @[ @{@"finished" : @YES, @"value" : @1} ]; - XCTAssertEqualObjects(response, expected); - }; - - [_nodesManager startAnimatingNode:@1 - nodeTag:@101 - config:@{@"type" : @"frames", @"frames" : frames, @"toValue" : @1} - endCallback:endCallback]; - - [_nodesManager stepAnimations:_displayLink]; - [_nodesManager stepAnimations:_displayLink]; - XCTAssertEqual(endCallbackCalls, 0); - [_nodesManager stepAnimations:_displayLink]; - XCTAssertEqual(endCallbackCalls, 1); - [_nodesManager stepAnimations:_displayLink]; - XCTAssertEqual(endCallbackCalls, 1); -} - -/** - * Creates a following graph of nodes: - * Value(1, firstValue) ----> Add(3) ---> Style(4) ---> Props(5) ---> View(viewTag) - * | - * Value(2, secondValue) --+ - * - * Add(3) node maps to a "translateX" attribute of the Style(4) node. - */ -- (void)createAnimatedGraphWithAdditionNode:(NSNumber *)viewTag - firstValue:(CGFloat)firstValue - secondValue:(CGFloat)secondValue -{ - [_nodesManager createAnimatedNode:@101 config:@{@"type" : @"value", @"value" : @(firstValue), @"offset" : @0}]; - [_nodesManager createAnimatedNode:@201 config:@{@"type" : @"value", @"value" : @(secondValue), @"offset" : @0}]; - [_nodesManager createAnimatedNode:@301 config:@{@"type" : @"addition", @"input" : @[ @101, @201 ]}]; - [_nodesManager createAnimatedNode:@401 config:@{@"type" : @"style", @"style" : @{@"translateX" : @301}}]; - [_nodesManager createAnimatedNode:@501 config:@{@"type" : @"props", @"props" : @{@"style" : @401}}]; - - [_nodesManager connectAnimatedNodes:@101 childTag:@301]; - [_nodesManager connectAnimatedNodes:@201 childTag:@301]; - [_nodesManager connectAnimatedNodes:@301 childTag:@401]; - [_nodesManager connectAnimatedNodes:@401 childTag:@501]; - [_nodesManager connectAnimatedNodeToView:@501 viewTag:viewTag viewName:@"UIView"]; -} - -- (void)testAdditionNode -{ - NSNumber *viewTag = @51; - [self createAnimatedGraphWithAdditionNode:viewTag firstValue:100 secondValue:1000]; - - NSArray *frames = @[ @0, @1 ]; - [_nodesManager startAnimatingNode:@1 - nodeTag:@101 - config:@{@"type" : @"frames", @"frames" : frames, @"toValue" : @101} - endCallback:nil]; - [_nodesManager startAnimatingNode:@2 - nodeTag:@201 - config:@{@"type" : @"frames", @"frames" : frames, @"toValue" : @1010} - endCallback:nil]; - - [[_uiManager expect] synchronouslyUpdateViewOnUIThread:viewTag - viewName:@"UIView" - props:RCTPropChecker(@"translateX", @1100)]; - [_nodesManager stepAnimations:_displayLink]; - [_uiManager verify]; - - [[_uiManager expect] synchronouslyUpdateViewOnUIThread:viewTag - viewName:@"UIView" - props:RCTPropChecker(@"translateX", @1111)]; - [_nodesManager stepAnimations:_displayLink]; - [_uiManager verify]; - - [[_uiManager expect] synchronouslyUpdateViewOnUIThread:viewTag - viewName:@"UIView" - props:RCTPropChecker(@"translateX", @1111)]; - [_nodesManager stepAnimations:_displayLink]; - [_uiManager verify]; - - [[_uiManager reject] synchronouslyUpdateViewOnUIThread:OCMOCK_ANY viewName:OCMOCK_ANY props:OCMOCK_ANY]; - [_nodesManager stepAnimations:_displayLink]; - [_uiManager verify]; -} - -/** - * Verifies that views are updated properly when one of the addition input nodes has started animating - * while the other one has not. - * - * We expect that the output of the addition node will take the starting value of the second input - * node even though the node hasn't been connected to an active animation driver. - */ -- (void)testViewReceiveUpdatesIfOneOfAnimationHasntStarted -{ - NSNumber *viewTag = @51; - [self createAnimatedGraphWithAdditionNode:viewTag firstValue:100 secondValue:1000]; - - NSArray *frames = @[ @0, @1 ]; - [_nodesManager startAnimatingNode:@1 - nodeTag:@101 - config:@{@"type" : @"frames", @"frames" : frames, @"toValue" : @101} - endCallback:nil]; - - [[_uiManager expect] synchronouslyUpdateViewOnUIThread:viewTag - viewName:@"UIView" - props:RCTPropChecker(@"translateX", @1100)]; - [_nodesManager stepAnimations:_displayLink]; - [_uiManager verify]; - - [[_uiManager expect] synchronouslyUpdateViewOnUIThread:viewTag - viewName:@"UIView" - props:RCTPropChecker(@"translateX", @1101)]; - [_nodesManager stepAnimations:_displayLink]; - [_uiManager verify]; - - [[_uiManager expect] synchronouslyUpdateViewOnUIThread:viewTag - viewName:@"UIView" - props:RCTPropChecker(@"translateX", @1101)]; - [_nodesManager stepAnimations:_displayLink]; - [_uiManager verify]; - - [[_uiManager reject] synchronouslyUpdateViewOnUIThread:OCMOCK_ANY viewName:OCMOCK_ANY props:OCMOCK_ANY]; - [_nodesManager stepAnimations:_displayLink]; - [_uiManager verify]; -} - -/** - * Verifies that views are updated properly when one of the addition input nodes animation finishes - * before the other. - * - * We expect that the output of the addition node after one of the animation has finished will - * take the last value of the animated node and the view will receive updates up until the second - * animation is over. - */ -- (void)testViewReceiveUpdatesWhenOneOfAnimationHasFinished -{ - NSNumber *viewTag = @51; - [self createAnimatedGraphWithAdditionNode:viewTag firstValue:100 secondValue:1000]; - - NSArray *firstFrames = @[ @0, @1 ]; - [_nodesManager startAnimatingNode:@1 - nodeTag:@101 - config:@{@"type" : @"frames", @"frames" : firstFrames, @"toValue" : @200} - endCallback:nil]; - NSArray *secondFrames = @[ @0, @0.2, @0.4, @0.6, @0.8, @1 ]; - [_nodesManager startAnimatingNode:@2 - nodeTag:@201 - config:@{@"type" : @"frames", @"frames" : secondFrames, @"toValue" : @1010} - endCallback:nil]; - - [[_uiManager expect] synchronouslyUpdateViewOnUIThread:viewTag - viewName:@"UIView" - props:RCTPropChecker(@"translateX", @1100)]; - [_nodesManager stepAnimations:_displayLink]; - [_uiManager verify]; - - for (NSUInteger i = 1; i < secondFrames.count; i++) { - CGFloat expected = 1200.0 + secondFrames[i].doubleValue * 10.0; - [[_uiManager expect] synchronouslyUpdateViewOnUIThread:viewTag - viewName:@"UIView" - props:RCTPropChecker(@"translateX", @(expected))]; - [_nodesManager stepAnimations:_displayLink]; - [_uiManager verify]; - } - - [[_uiManager expect] synchronouslyUpdateViewOnUIThread:viewTag - viewName:@"UIView" - props:RCTPropChecker(@"translateX", @1210)]; - [_nodesManager stepAnimations:_displayLink]; - [_uiManager verify]; - - [[_uiManager reject] synchronouslyUpdateViewOnUIThread:OCMOCK_ANY viewName:OCMOCK_ANY props:OCMOCK_ANY]; - [_nodesManager stepAnimations:_displayLink]; - [_uiManager verify]; -} - -- (void)testMultiplicationNode -{ - NSNumber *viewTag = @51; - [_nodesManager createAnimatedNode:@101 config:@{@"type" : @"value", @"value" : @1, @"offset" : @0}]; - [_nodesManager createAnimatedNode:@201 config:@{@"type" : @"value", @"value" : @5, @"offset" : @0}]; - [_nodesManager createAnimatedNode:@301 config:@{@"type" : @"multiplication", @"input" : @[ @101, @201 ]}]; - [_nodesManager createAnimatedNode:@401 config:@{@"type" : @"style", @"style" : @{@"translateX" : @301}}]; - [_nodesManager createAnimatedNode:@501 config:@{@"type" : @"props", @"props" : @{@"style" : @401}}]; - - [_nodesManager connectAnimatedNodes:@101 childTag:@301]; - [_nodesManager connectAnimatedNodes:@201 childTag:@301]; - [_nodesManager connectAnimatedNodes:@301 childTag:@401]; - [_nodesManager connectAnimatedNodes:@401 childTag:@501]; - [_nodesManager connectAnimatedNodeToView:@501 viewTag:viewTag viewName:@"UIView"]; - - NSArray *frames = @[ @0, @1 ]; - [_nodesManager startAnimatingNode:@1 - nodeTag:@101 - config:@{@"type" : @"frames", @"frames" : frames, @"toValue" : @2} - endCallback:nil]; - [_nodesManager startAnimatingNode:@2 - nodeTag:@201 - config:@{@"type" : @"frames", @"frames" : frames, @"toValue" : @10} - endCallback:nil]; - - [[_uiManager expect] synchronouslyUpdateViewOnUIThread:viewTag - viewName:@"UIView" - props:RCTPropChecker(@"translateX", @5)]; - [_nodesManager stepAnimations:_displayLink]; - [_uiManager verify]; - - [[_uiManager expect] synchronouslyUpdateViewOnUIThread:viewTag - viewName:@"UIView" - props:RCTPropChecker(@"translateX", @20)]; - [_nodesManager stepAnimations:_displayLink]; - [_uiManager verify]; - - [[_uiManager expect] synchronouslyUpdateViewOnUIThread:viewTag - viewName:@"UIView" - props:RCTPropChecker(@"translateX", @20)]; - [_nodesManager stepAnimations:_displayLink]; - [_uiManager verify]; - - [[_uiManager reject] synchronouslyUpdateViewOnUIThread:OCMOCK_ANY viewName:OCMOCK_ANY props:OCMOCK_ANY]; - [_nodesManager stepAnimations:_displayLink]; - [_uiManager verify]; -} - -- (void)testHandleStoppingAnimation -{ - [self createSimpleAnimatedView:@1001 withOpacity:0]; - NSArray *frames = @[ @0, @0.2, @0.4, @0.6, @0.8, @1 ]; - - __block BOOL endCallbackCalled = NO; - - RCTResponseSenderBlock endCallback = ^(NSArray *response) { - endCallbackCalled = YES; - XCTAssertEqual(response.count, 1); - XCTAssertEqualObjects(response[0][@"finished"], @NO); - }; - - [_nodesManager startAnimatingNode:@404 - nodeTag:@101 - config:@{@"type" : @"frames", @"frames" : frames, @"toValue" : @1} - endCallback:endCallback]; - - [[_uiManager expect] synchronouslyUpdateViewOnUIThread:OCMOCK_ANY viewName:OCMOCK_ANY props:OCMOCK_ANY]; - [_nodesManager stepAnimations:_displayLink]; - [_uiManager verify]; - [[_uiManager expect] synchronouslyUpdateViewOnUIThread:OCMOCK_ANY viewName:OCMOCK_ANY props:OCMOCK_ANY]; - [_nodesManager stepAnimations:_displayLink]; - [_uiManager verify]; - - [_nodesManager stopAnimation:@404]; - XCTAssertEqual(endCallbackCalled, YES); - - // Run "update" loop a few more times -> we expect no further updates nor callback calls to be - // triggered - for (NSUInteger i = 0; i < 5; i++) { - [[_uiManager reject] synchronouslyUpdateViewOnUIThread:OCMOCK_ANY viewName:OCMOCK_ANY props:OCMOCK_ANY]; - [_nodesManager stepAnimations:_displayLink]; - [_uiManager verify]; - } -} - -- (void)testInterpolationNode -{ - NSNumber *viewTag = @51; - [_nodesManager createAnimatedNode:@101 config:@{@"type" : @"value", @"value" : @10, @"offset" : @0}]; - [_nodesManager createAnimatedNode:@201 - config:@{ - @"type" : @"interpolation", - @"inputRange" : @[ @10, @20 ], - @"outputRange" : @[ @0, @1 ], - @"extrapolateLeft" : @"extend", - @"extrapolateRight" : @"extend" - }]; - [_nodesManager createAnimatedNode:@301 config:@{@"type" : @"style", @"style" : @{@"opacity" : @201}}]; - [_nodesManager createAnimatedNode:@401 config:@{@"type" : @"props", @"props" : @{@"style" : @301}}]; - - [_nodesManager connectAnimatedNodes:@101 childTag:@201]; - [_nodesManager connectAnimatedNodes:@201 childTag:@301]; - [_nodesManager connectAnimatedNodes:@301 childTag:@401]; - [_nodesManager connectAnimatedNodeToView:@401 viewTag:viewTag viewName:@"UIView"]; - - NSArray *frames = @[ @0, @0.2, @0.4, @0.6, @0.8, @1 ]; - [_nodesManager startAnimatingNode:@1 - nodeTag:@101 - config:@{@"type" : @"frames", @"frames" : frames, @"toValue" : @20} - endCallback:nil]; - - for (NSNumber *frame in frames) { - [[_uiManager expect] synchronouslyUpdateViewOnUIThread:viewTag - viewName:@"UIView" - props:RCTPropChecker(@"opacity", frame)]; - [_nodesManager stepAnimations:_displayLink]; - [_uiManager verify]; - } - - [[_uiManager expect] synchronouslyUpdateViewOnUIThread:viewTag - viewName:@"UIView" - props:RCTPropChecker(@"opacity", @1)]; - [_nodesManager stepAnimations:_displayLink]; - [_uiManager verify]; - - [[_uiManager reject] synchronouslyUpdateViewOnUIThread:OCMOCK_ANY viewName:OCMOCK_ANY props:OCMOCK_ANY]; - [_nodesManager stepAnimations:_displayLink]; - [_uiManager verify]; -} - -- (id)createScrollEventWithTag:(NSNumber *)viewTag value:(CGFloat)value -{ - // The event value is the 3rd argument. - NSArray *arguments = @[ @1, @1, @{@"contentOffset" : @{@"y" : @(value)}} ]; - return [[RCTFakeEvent alloc] initWithName:@"topScroll" viewTag:viewTag arguments:arguments]; -} - -- (void)testNativeAnimatedEventDoUpdate -{ - NSNumber *viewTag = @1001; - [self createSimpleAnimatedView:viewTag withOpacity:0]; - - [_nodesManager - addAnimatedEventToView:viewTag - eventName:@"topScroll" - eventMapping:@{@"animatedValueTag" : @101, @"nativeEventPath" : @[ @"contentOffset", @"y" ]}]; - - // Make sure that the update actually happened synchronously in `handleAnimatedEvent` and does - // not wait for the next animation loop. - [[_uiManager expect] synchronouslyUpdateViewOnUIThread:viewTag - viewName:@"UIView" - props:RCTPropChecker(@"opacity", @10)]; - [_nodesManager handleAnimatedEvent:[self createScrollEventWithTag:viewTag value:10]]; - [_uiManager verify]; - - [[_uiManager reject] synchronouslyUpdateViewOnUIThread:OCMOCK_ANY viewName:OCMOCK_ANY props:OCMOCK_ANY]; - [_nodesManager stepAnimations:_displayLink]; - [_uiManager verify]; -} - -- (void)testNativeAnimatedEventDoNotUpdate -{ - NSNumber *viewTag = @1001; - [self createSimpleAnimatedView:viewTag withOpacity:0]; - - [_nodesManager - addAnimatedEventToView:viewTag - eventName:@"otherEvent" - eventMapping:@{@"animatedValueTag" : @101, @"nativeEventPath" : @[ @"contentOffset", @"y" ]}]; - - [_nodesManager - addAnimatedEventToView:@999 - eventName:@"topScroll" - eventMapping:@{@"animatedValueTag" : @101, @"nativeEventPath" : @[ @"contentOffset", @"y" ]}]; - - [[_uiManager reject] synchronouslyUpdateViewOnUIThread:OCMOCK_ANY viewName:OCMOCK_ANY props:OCMOCK_ANY]; - [_nodesManager handleAnimatedEvent:[self createScrollEventWithTag:viewTag value:10]]; - [_uiManager verify]; -} - -- (void)testGetValue -{ - __block NSInteger saveValueCallbackCalls = 0; - NSNumber *nodeTag = @100; - [_nodesManager createAnimatedNode:nodeTag config:@{@"type" : @"value", @"value" : @1, @"offset" : @0}]; - RCTResponseSenderBlock saveValueCallback = ^(NSArray *response) { - saveValueCallbackCalls++; - XCTAssertEqualObjects(response, @[ @1 ]); - }; - - XCTAssertEqual(saveValueCallbackCalls, 0); - - [_nodesManager getValue:nodeTag saveCallback:saveValueCallback]; - XCTAssertEqual(saveValueCallbackCalls, 1); -} - -/** - * Creates a following graph of nodes: - * Value(3, initialValue) ----> Style(4) ---> Props(5) ---> View(viewTag) - * - * Value(3) is set to track Value(1) via Tracking(2) node with the provided animation config - */ -- (void)createAnimatedGraphWithTrackingNode:(NSNumber *)viewTag - initialValue:(CGFloat)initialValue - animationConfig:(NSDictionary *)animationConfig -{ - [_nodesManager createAnimatedNode:@101 config:@{@"type" : @"value", @"value" : @(initialValue), @"offset" : @0}]; - [_nodesManager createAnimatedNode:@301 config:@{@"type" : @"value", @"value" : @(initialValue), @"offset" : @0}]; - - [_nodesManager createAnimatedNode:@201 - config:@{ - @"type" : @"tracking", - @"animationId" : @70, - @"value" : @301, - @"toValue" : @101, - @"animationConfig" : animationConfig - }]; - [_nodesManager createAnimatedNode:@401 config:@{@"type" : @"style", @"style" : @{@"translateX" : @301}}]; - [_nodesManager createAnimatedNode:@501 config:@{@"type" : @"props", @"props" : @{@"style" : @401}}]; - - [_nodesManager connectAnimatedNodes:@101 childTag:@201]; - [_nodesManager connectAnimatedNodes:@301 childTag:@401]; - [_nodesManager connectAnimatedNodes:@401 childTag:@501]; - [_nodesManager connectAnimatedNodeToView:@501 viewTag:viewTag viewName:@"UIView"]; -} - -/** - * In this test we verify that when value is being tracked we can update destination value in the - * middle of ongoing animation and the animation will update and animate to the new spot. This is - * tested using simple 5 frame backed timing animation. - */ -- (void)testTracking -{ - NSArray *frames = @[ @0, @0.25, @0.5, @0.75, @1 ]; - NSDictionary *animationConfig = @{@"type" : @"frames", @"frames" : frames}; - [self createAnimatedGraphWithTrackingNode:@1001 initialValue:0 animationConfig:animationConfig]; - [_nodesManager stepAnimations:_displayLink]; // kick off the tracking - - [[_uiManager expect] synchronouslyUpdateViewOnUIThread:@1001 - viewName:@"UIView" - props:RCTPropChecker(@"translateX", 0)]; - [_nodesManager stepAnimations:_displayLink]; - [_uiManager verify]; - - // update "toValue" to 100, we expect tracking animation to animate now from 0 to 100 in 5 steps - [_nodesManager setAnimatedNodeValue:@101 value:@100]; - [_nodesManager stepAnimations:_displayLink]; // kick off the tracking - - for (NSNumber *frame in frames) { - NSNumber *expected = @([frame doubleValue] * 100); - [[_uiManager expect] synchronouslyUpdateViewOnUIThread:@1001 - viewName:@"UIView" - props:RCTPropChecker(@"translateX", expected)]; - [_nodesManager stepAnimations:_displayLink]; - [_uiManager verify]; - } - - // update "toValue" to 0 but run only two frames from the animation, - // we expect tracking animation to animate now from 100 to 75 - [_nodesManager setAnimatedNodeValue:@101 value:@0]; - [_nodesManager stepAnimations:_displayLink]; // kick off the tracking - - for (int i = 0; i < 2; i++) { - NSNumber *expected = @(100. * (1. - [frames[i] doubleValue])); - [[_uiManager expect] synchronouslyUpdateViewOnUIThread:@1001 - viewName:@"UIView" - props:RCTPropChecker(@"translateX", expected)]; - [_nodesManager stepAnimations:_displayLink]; - [_uiManager verify]; - } - - // at this point we expect tracking value to be at 75 - // we update "toValue" again to 100 and expect the animation to restart from the current place - [_nodesManager setAnimatedNodeValue:@101 value:@100]; - [_nodesManager stepAnimations:_displayLink]; // kick off the tracking - - for (NSNumber *frame in frames) { - NSNumber *expected = @(50. + 50. * [frame doubleValue]); - [[_uiManager expect] synchronouslyUpdateViewOnUIThread:@1001 - viewName:@"UIView" - props:RCTPropChecker(@"translateX", expected)]; - [_nodesManager stepAnimations:_displayLink]; - [_uiManager verify]; - } - - [_nodesManager stepAnimations:_displayLink]; - [[_uiManager reject] synchronouslyUpdateViewOnUIThread:OCMOCK_ANY viewName:OCMOCK_ANY props:OCMOCK_ANY]; - [_nodesManager stepAnimations:_displayLink]; - [_uiManager verify]; -} - -/** - * In this test we verify that when tracking is set up for a given animated node and when the - * animation settles it will not be registered as an active animation and therefore will not - * consume resources on running the animation that has already completed. Then we verify that when - * the value updates the animation will resume as expected and the complete again when reaches the - * end. - */ - -- (void)testTrackingPausesWhenEndValueIsReached -{ - NSArray *frames = @[ @0, @0.5, @1 ]; - NSDictionary *animationConfig = @{@"type" : @"frames", @"frames" : frames}; - [self createAnimatedGraphWithTrackingNode:@1001 initialValue:0 animationConfig:animationConfig]; - - [_nodesManager setAnimatedNodeValue:@101 value:@100]; - [_nodesManager stepAnimations:_displayLink]; // kick off the tracking - - __block int callCount = 0; - [[[_uiManager stub] andDo:^(NSInvocation *__unused invocation) { - callCount++; - }] synchronouslyUpdateViewOnUIThread:OCMOCK_ANY viewName:OCMOCK_ANY props:OCMOCK_ANY]; - - for (NSUInteger i = 0; i < frames.count; i++) { - [_nodesManager stepAnimations:_displayLink]; - } - [_nodesManager stepAnimations:_displayLink]; - XCTAssertEqual(callCount, 4); - - // the animation has completed, we expect no updates to be done - [[[_uiManager stub] andDo:^(NSInvocation *__unused invocation) { - XCTFail("Expected not to be called"); - }] synchronouslyUpdateViewOnUIThread:OCMOCK_ANY viewName:OCMOCK_ANY props:OCMOCK_ANY]; - [_nodesManager stepAnimations:_displayLink]; - [_uiManager verify]; - - // restore rejected method, we will use it later on - callCount = 0; - [[[_uiManager stub] andDo:^(NSInvocation *__unused invocation) { - callCount++; - }] synchronouslyUpdateViewOnUIThread:OCMOCK_ANY viewName:OCMOCK_ANY props:OCMOCK_ANY]; - - // we update end value and expect the animation to restart - [_nodesManager setAnimatedNodeValue:@101 value:@200]; - [_nodesManager stepAnimations:_displayLink]; // kick off the tracking - - for (NSUInteger i = 0; i < frames.count; i++) { - [_nodesManager stepAnimations:_displayLink]; - } - [_nodesManager stepAnimations:_displayLink]; - XCTAssertEqual(callCount, 4); - - // the animation has completed, we expect no updates to be done - [[_uiManager reject] synchronouslyUpdateViewOnUIThread:OCMOCK_ANY viewName:OCMOCK_ANY props:OCMOCK_ANY]; - [_nodesManager stepAnimations:_displayLink]; - [_uiManager verify]; -} - -/** - * In this test we verify that when tracking is configured to use spring animation and when the - * destination value updates the current speed of the animated value will be taken into account - * while updating the spring animation and it will smoothly transition to the new end value. - */ -- (void)testSpringTrackingRetainsSpeed -{ - // this spring config corresponds to tension 20 and friction 0.5 which makes the spring settle - // very slowly - NSDictionary *springConfig = @{ - @"type" : @"spring", - @"restSpeedThreshold" : @0.001, - @"mass" : @1, - @"restDisplacementThreshold" : @0.001, - @"initialVelocity" : @0.5, - @"damping" : @2.5, - @"stiffness" : @157.8, - @"overshootClamping" : @NO - }; - [self createAnimatedGraphWithTrackingNode:@1001 initialValue:0 animationConfig:springConfig]; - - __block CGFloat lastTranslateX = 0; - [[[_uiManager stub] andDo:^(NSInvocation *invocation) { - __unsafe_unretained NSDictionary *props = nil; - [invocation getArgument:&props atIndex:4]; - lastTranslateX = [props[@"translateX"] doubleValue]; - }] synchronouslyUpdateViewOnUIThread:OCMOCK_ANY viewName:OCMOCK_ANY props:OCMOCK_ANY]; - - // update "toValue" to 1, we expect tracking animation to animate now from 0 to 1 - [_nodesManager setAnimatedNodeValue:@101 value:@1]; - [_nodesManager stepAnimations:_displayLink]; // kick off the tracking - - // we run several steps of animation until the value starts bouncing, has negative speed and - // passes the final point (that is 1) while going backwards - BOOL isBoucingBack = NO; - CGFloat previousValue = 0; - for (int maxFrames = 500; maxFrames > 0; maxFrames--) { - [_nodesManager stepAnimations:_displayLink]; // kick off the tracking - if (previousValue >= 1. && lastTranslateX < 1.) { - isBoucingBack = YES; - break; - } - previousValue = lastTranslateX; - } - XCTAssert(isBoucingBack); - - // we now update "toValue" to 1.5 but since the value have negative speed and has also pretty - // low friction we expect it to keep going in the opposite direction for a few more frames - [_nodesManager setAnimatedNodeValue:@101 value:@1.5]; - [_nodesManager stepAnimations:_displayLink]; // kick off the tracking - - int bounceBackInitialFrames = 0; - BOOL hasTurnedForward = NO; - - // we run 8 seconds of animation - for (int i = 0; i < 8 * 60; i++) { - [_nodesManager stepAnimations:_displayLink]; - if (!hasTurnedForward) { - if (lastTranslateX <= previousValue) { - bounceBackInitialFrames++; - } else { - hasTurnedForward = true; - } - } - previousValue = lastTranslateX; - } - XCTAssert(hasTurnedForward); - XCTAssertGreaterThan(bounceBackInitialFrames, 3); - XCTAssertEqual(lastTranslateX, 1.5); -} - -@end diff --git a/packages/rn-tester/RNTesterUnitTests/RCTNetworkTaskTests.m b/packages/rn-tester/RNTesterUnitTests/RCTNetworkTaskTests.m deleted file mode 100644 index 874875ee0f9199..00000000000000 --- a/packages/rn-tester/RNTesterUnitTests/RCTNetworkTaskTests.m +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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 -#import -#import - -@interface TestHandler : NSObject -@end - -@implementation TestHandler -- (BOOL)canHandleRequest:(NSURLRequest *)request -{ - return YES; -} -- (id)sendRequest:(NSURLRequest *)request withDelegate:(id)delegate -{ - return [[NSUUID UUID] UUIDString]; -} -@end - -@interface RCTNetworkTaskTests : XCTestCase - -@end - -@implementation RCTNetworkTaskTests - -- (void)testCanReadTaskStatus -{ - NSURL *url = [[NSURL alloc] initWithString:@"https://developers.facebook.com"]; - NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url]; - dispatch_queue_t callbackQueue = - dispatch_queue_create("RCTNetworkTaskTests-testCanReadTaskStatus", DISPATCH_QUEUE_SERIAL); - id testHandler = (id)[[TestHandler alloc] init]; - RCTNetworkTask *task = [[RCTNetworkTask alloc] initWithRequest:request - handler:testHandler - callbackQueue:callbackQueue]; - XCTAssertEqual(task.status, RCTNetworkTaskPending); - [task start]; - XCTAssertEqual(task.status, RCTNetworkTaskInProgress); - [task cancel]; - XCTAssertEqual(task.status, RCTNetworkTaskFinished); -} - -@end diff --git a/packages/rn-tester/RNTesterUnitTests/RCTPerformanceLoggerTests.m b/packages/rn-tester/RNTesterUnitTests/RCTPerformanceLoggerTests.m deleted file mode 100644 index 51f4c07e3e74ca..00000000000000 --- a/packages/rn-tester/RNTesterUnitTests/RCTPerformanceLoggerTests.m +++ /dev/null @@ -1,18 +0,0 @@ -/* - * 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 - -#import - -@interface RCTPerformanceLoggerTests : XCTestCase - -@end - -@implementation RCTPerformanceLoggerTests - -@end diff --git a/packages/rn-tester/RNTesterUnitTests/RCTShadowViewTests.m b/packages/rn-tester/RNTesterUnitTests/RCTShadowViewTests.m deleted file mode 100644 index f63a54b327a8b5..00000000000000 --- a/packages/rn-tester/RNTesterUnitTests/RCTShadowViewTests.m +++ /dev/null @@ -1,206 +0,0 @@ -/* - * 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 - -#import -#import -#import - -@interface RCTShadowViewTests : XCTestCase -@property (nonatomic, strong) RCTRootShadowView *parentView; -@end - -@implementation RCTShadowViewTests - -- (void)setUp -{ - [super setUp]; - - self.parentView = [RCTRootShadowView new]; - YGNodeStyleSetFlexDirection(self.parentView.yogaNode, YGFlexDirectionColumn); - YGNodeStyleSetWidth(self.parentView.yogaNode, 440); - YGNodeStyleSetHeight(self.parentView.yogaNode, 440); - self.parentView.reactTag = @1; // must be valid rootView tag -} - -// Just a basic sanity test to ensure css-layout is applied correctly in the context of our shadow view hierarchy. -// -// ==================================== -// || header || -// ==================================== -// || || || || -// || left || center || right || -// || || || || -// ==================================== -// || footer || -// ==================================== -// -- (void)testApplyingLayoutRecursivelyToShadowView -{ - RCTShadowView *leftView = [self _shadowViewWithConfig:^(YGNodeRef node) { - YGNodeStyleSetFlex(node, 1); - }]; - - RCTShadowView *centerView = [self _shadowViewWithConfig:^(YGNodeRef node) { - YGNodeStyleSetFlex(node, 2); - YGNodeStyleSetMargin(node, YGEdgeLeft, 10); - YGNodeStyleSetMargin(node, YGEdgeRight, 10); - }]; - - RCTShadowView *rightView = [self _shadowViewWithConfig:^(YGNodeRef node) { - YGNodeStyleSetFlex(node, 1); - }]; - - RCTShadowView *mainView = [self _shadowViewWithConfig:^(YGNodeRef node) { - YGNodeStyleSetFlexDirection(node, YGFlexDirectionRow); - YGNodeStyleSetFlex(node, 2); - YGNodeStyleSetMargin(node, YGEdgeTop, 10); - YGNodeStyleSetMargin(node, YGEdgeBottom, 10); - }]; - - [mainView insertReactSubview:leftView atIndex:0]; - [mainView insertReactSubview:centerView atIndex:1]; - [mainView insertReactSubview:rightView atIndex:2]; - - RCTShadowView *headerView = [self _shadowViewWithConfig:^(YGNodeRef node) { - YGNodeStyleSetFlex(node, 1); - }]; - - RCTShadowView *footerView = [self _shadowViewWithConfig:^(YGNodeRef node) { - YGNodeStyleSetFlex(node, 1); - }]; - - YGNodeStyleSetPadding(self.parentView.yogaNode, YGEdgeLeft, 10); - YGNodeStyleSetPadding(self.parentView.yogaNode, YGEdgeTop, 10); - YGNodeStyleSetPadding(self.parentView.yogaNode, YGEdgeRight, 10); - YGNodeStyleSetPadding(self.parentView.yogaNode, YGEdgeBottom, 10); - - [self.parentView insertReactSubview:headerView atIndex:0]; - [self.parentView insertReactSubview:mainView atIndex:1]; - [self.parentView insertReactSubview:footerView atIndex:2]; - - [self.parentView layoutWithAffectedShadowViews:[NSPointerArray weakObjectsPointerArray]]; - - XCTAssertTrue( - CGRectEqualToRect([self.parentView measureLayoutRelativeToAncestor:self.parentView], CGRectMake(0, 0, 440, 440))); - XCTAssertTrue(UIEdgeInsetsEqualToEdgeInsets([self.parentView paddingAsInsets], UIEdgeInsetsMake(10, 10, 10, 10))); - - XCTAssertTrue( - CGRectEqualToRect([headerView measureLayoutRelativeToAncestor:self.parentView], CGRectMake(10, 10, 420, 100))); - XCTAssertTrue( - CGRectEqualToRect([mainView measureLayoutRelativeToAncestor:self.parentView], CGRectMake(10, 120, 420, 200))); - XCTAssertTrue( - CGRectEqualToRect([footerView measureLayoutRelativeToAncestor:self.parentView], CGRectMake(10, 330, 420, 100))); - - XCTAssertTrue( - CGRectEqualToRect([leftView measureLayoutRelativeToAncestor:self.parentView], CGRectMake(10, 120, 100, 200))); - XCTAssertTrue( - CGRectEqualToRect([centerView measureLayoutRelativeToAncestor:self.parentView], CGRectMake(120, 120, 200, 200))); - XCTAssertTrue( - CGRectEqualToRect([rightView measureLayoutRelativeToAncestor:self.parentView], CGRectMake(330, 120, 100, 200))); -} - -- (void)testAncestorCheck -{ - RCTShadowView *centerView = [self _shadowViewWithConfig:^(YGNodeRef node) { - YGNodeStyleSetFlex(node, 1); - }]; - - RCTShadowView *mainView = [self _shadowViewWithConfig:^(YGNodeRef node) { - YGNodeStyleSetFlex(node, 1); - }]; - - [mainView insertReactSubview:centerView atIndex:0]; - - RCTShadowView *footerView = [self _shadowViewWithConfig:^(YGNodeRef node) { - YGNodeStyleSetFlex(node, 1); - }]; - - [self.parentView insertReactSubview:mainView atIndex:0]; - [self.parentView insertReactSubview:footerView atIndex:1]; - - XCTAssertTrue([centerView viewIsDescendantOf:mainView]); - XCTAssertFalse([footerView viewIsDescendantOf:mainView]); -} - -- (void)testAssignsSuggestedWidthDimension -{ - [self - _withShadowViewWithStyle:^(YGNodeRef node) { - YGNodeStyleSetPositionType(node, YGPositionTypeAbsolute); - YGNodeStyleSetPosition(node, YGEdgeLeft, 0); - YGNodeStyleSetPosition(node, YGEdgeTop, 0); - YGNodeStyleSetHeight(node, 10); - } - assertRelativeLayout:CGRectMake(0, 0, 3, 10) - withIntrinsicContentSize:CGSizeMake(3, UIViewNoIntrinsicMetric)]; -} - -- (void)testAssignsSuggestedHeightDimension -{ - [self - _withShadowViewWithStyle:^(YGNodeRef node) { - YGNodeStyleSetPositionType(node, YGPositionTypeAbsolute); - YGNodeStyleSetPosition(node, YGEdgeLeft, 0); - YGNodeStyleSetPosition(node, YGEdgeTop, 0); - YGNodeStyleSetWidth(node, 10); - } - assertRelativeLayout:CGRectMake(0, 0, 10, 4) - withIntrinsicContentSize:CGSizeMake(UIViewNoIntrinsicMetric, 4)]; -} - -- (void)testDoesNotOverrideDimensionStyleWithSuggestedDimensions -{ - [self - _withShadowViewWithStyle:^(YGNodeRef node) { - YGNodeStyleSetPositionType(node, YGPositionTypeAbsolute); - YGNodeStyleSetPosition(node, YGEdgeLeft, 0); - YGNodeStyleSetPosition(node, YGEdgeTop, 0); - YGNodeStyleSetWidth(node, 10); - YGNodeStyleSetHeight(node, 10); - } - assertRelativeLayout:CGRectMake(0, 0, 10, 10) - withIntrinsicContentSize:CGSizeMake(3, 4)]; -} - -- (void)testDoesNotAssignSuggestedDimensionsWhenStyledWithFlexAttribute -{ - float parentWidth = YGNodeStyleGetWidth(self.parentView.yogaNode).value; - float parentHeight = YGNodeStyleGetHeight(self.parentView.yogaNode).value; - [self - _withShadowViewWithStyle:^(YGNodeRef node) { - YGNodeStyleSetFlex(node, 1); - } - assertRelativeLayout:CGRectMake(0, 0, parentWidth, parentHeight) - withIntrinsicContentSize:CGSizeMake(3, 4)]; -} - -- (void)_withShadowViewWithStyle:(void (^)(YGNodeRef node))configBlock - assertRelativeLayout:(CGRect)expectedRect - withIntrinsicContentSize:(CGSize)contentSize -{ - RCTShadowView *view = [self _shadowViewWithConfig:configBlock]; - [self.parentView insertReactSubview:view atIndex:0]; - view.intrinsicContentSize = contentSize; - [self.parentView layoutWithAffectedShadowViews:[NSPointerArray weakObjectsPointerArray]]; - CGRect actualRect = [view measureLayoutRelativeToAncestor:self.parentView]; - XCTAssertTrue( - CGRectEqualToRect(expectedRect, actualRect), - @"Expected layout to be %@, got %@", - NSStringFromCGRect(expectedRect), - NSStringFromCGRect(actualRect)); -} - -- (RCTShadowView *)_shadowViewWithConfig:(void (^)(YGNodeRef node))configBlock -{ - RCTShadowView *shadowView = [RCTShadowView new]; - configBlock(shadowView.yogaNode); - return shadowView; -} - -@end diff --git a/packages/rn-tester/RNTesterUnitTests/RCTUIManagerTests.m b/packages/rn-tester/RNTesterUnitTests/RCTUIManagerTests.m deleted file mode 100644 index c0166ae6b7879c..00000000000000 --- a/packages/rn-tester/RNTesterUnitTests/RCTUIManagerTests.m +++ /dev/null @@ -1,200 +0,0 @@ -/* - * 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 - -#import -#import - -@interface RCTUIManager (Testing) - -- (void)_manageChildren:(NSNumber *)containerReactTag - moveFromIndices:(NSArray *)moveFromIndices - moveToIndices:(NSArray *)moveToIndices - addChildReactTags:(NSArray *)addChildReactTags - addAtIndices:(NSArray *)addAtIndices - removeAtIndices:(NSArray *)removeAtIndices - registry:(NSDictionary> *)registry; - -@property (nonatomic, copy, readonly) NSMutableDictionary *viewRegistry; - -@end - -@interface RCTUIManagerTests : XCTestCase - -@property (nonatomic, readwrite, strong) RCTUIManager *uiManager; - -@end - -@implementation RCTUIManagerTests - -- (void)setUp -{ - [super setUp]; - - _uiManager = [RCTUIManager new]; - - // Register 20 views to use in the tests - for (NSInteger i = 1; i <= 20; i++) { - UIView *registeredView = [UIView new]; - registeredView.reactTag = @(i); - _uiManager.viewRegistry[@(i)] = registeredView; - } -} - -- (void)testManagingChildrenToAddViews -{ - UIView *containerView = _uiManager.viewRegistry[@20]; - NSMutableArray *addedViews = [NSMutableArray array]; - - NSArray *tagsToAdd = @[ @1, @2, @3, @4, @5 ]; - NSArray *addAtIndices = @[ @0, @1, @2, @3, @4 ]; - for (NSNumber *tag in tagsToAdd) { - [addedViews addObject:_uiManager.viewRegistry[tag]]; - } - - // Add views 1-5 to view 20 - [_uiManager _manageChildren:@20 - moveFromIndices:nil - moveToIndices:nil - addChildReactTags:tagsToAdd - addAtIndices:addAtIndices - removeAtIndices:nil - registry:_uiManager.viewRegistry]; - - [containerView didUpdateReactSubviews]; - - XCTAssertTrue( - [[containerView reactSubviews] count] == 5, - @"Expect to have 5 react subviews after calling manage children \ - with 5 tags to add, instead have %lu", - (unsigned long)[[containerView reactSubviews] count]); - for (UIView *view in addedViews) { - XCTAssertTrue( - [view reactSuperview] == containerView, @"Expected to have manage children successfully add children"); - [view removeFromSuperview]; - } -} - -- (void)testManagingChildrenToRemoveViews -{ - UIView *containerView = _uiManager.viewRegistry[@20]; - NSMutableArray *removedViews = [NSMutableArray array]; - - NSArray *removeAtIndices = @[ @0, @4, @8, @12, @16 ]; - for (NSNumber *index in removeAtIndices) { - NSNumber *reactTag = @(index.integerValue + 2); - [removedViews addObject:_uiManager.viewRegistry[reactTag]]; - } - for (NSInteger i = 2; i < 20; i++) { - UIView *view = _uiManager.viewRegistry[@(i)]; - [containerView insertReactSubview:view atIndex:containerView.reactSubviews.count]; - } - - // Remove views 1-5 from view 20 - [_uiManager _manageChildren:@20 - moveFromIndices:nil - moveToIndices:nil - addChildReactTags:nil - addAtIndices:nil - removeAtIndices:removeAtIndices - registry:_uiManager.viewRegistry]; - - [containerView didUpdateReactSubviews]; - - XCTAssertEqual( - containerView.reactSubviews.count, - (NSUInteger)13, - @"Expect to have 13 react subviews after calling manage children\ - with 5 tags to remove and 18 prior children, instead have %zd", - containerView.reactSubviews.count); - for (UIView *view in removedViews) { - XCTAssertTrue([view reactSuperview] == nil, @"Expected to have manage children successfully remove children"); - // After removing views are unregistered - we need to reregister - _uiManager.viewRegistry[view.reactTag] = view; - } - for (NSInteger i = 2; i < 20; i++) { - UIView *view = _uiManager.viewRegistry[@(i)]; - if (![removedViews containsObject:view]) { - XCTAssertTrue( - [view superview] == containerView, - @"Should not have removed view with react tag %ld during delete but did", - (long)i); - [view removeFromSuperview]; - } - } -} - -// We want to start with views 1-10 added at indices 0-9 -// Then we'll remove indices 2, 3, 5 and 8 -// Add views 11 and 12 to indices 0 and 6 -// And move indices 4 and 9 to 1 and 7 -// So in total it goes from: -// [1,2,3,4,5,6,7,8,9,10] -// to -// [11,5,1,2,7,8,12,10] -- (void)testManagingChildrenToAddRemoveAndMove -{ - UIView *containerView = _uiManager.viewRegistry[@20]; - - NSArray *removeAtIndices = @[ @2, @3, @5, @8 ]; - NSArray *addAtIndices = @[ @0, @6 ]; - NSArray *tagsToAdd = @[ @11, @12 ]; - NSArray *moveFromIndices = @[ @4, @9 ]; - NSArray *moveToIndices = @[ @1, @7 ]; - - // We need to keep these in array to keep them around - NSMutableArray *viewsToRemove = [NSMutableArray array]; - for (NSUInteger i = 0; i < removeAtIndices.count; i++) { - NSNumber *reactTagToRemove = @([removeAtIndices[i] integerValue] + 1); - UIView *viewToRemove = _uiManager.viewRegistry[reactTagToRemove]; - [viewsToRemove addObject:viewToRemove]; - } - - for (NSInteger i = 1; i < 11; i++) { - UIView *view = _uiManager.viewRegistry[@(i)]; - [containerView insertReactSubview:view atIndex:containerView.reactSubviews.count]; - } - - [_uiManager _manageChildren:@20 - moveFromIndices:moveFromIndices - moveToIndices:moveToIndices - addChildReactTags:tagsToAdd - addAtIndices:addAtIndices - removeAtIndices:removeAtIndices - registry:_uiManager.viewRegistry]; - - [containerView didUpdateReactSubviews]; - - XCTAssertTrue( - [[containerView reactSubviews] count] == 8, - @"Expect to have 8 react subviews after calling manage children,\ - instead have the following subviews %@", - [containerView reactSubviews]); - - NSArray *expectedReactTags = @[ @11, @5, @1, @2, @7, @8, @12, @10 ]; - for (NSUInteger i = 0; i < containerView.subviews.count; i++) { - XCTAssertEqualObjects( - [[containerView reactSubviews][i] reactTag], - expectedReactTags[i], - @"Expected subview at index %ld to have react tag #%@ but has tag #%@", - (long)i, - expectedReactTags[i], - [[containerView reactSubviews][i] reactTag]); - } - - // Clean up after ourselves - for (NSInteger i = 1; i < 13; i++) { - UIView *view = _uiManager.viewRegistry[@(i)]; - [view removeFromSuperview]; - } - for (UIView *view in viewsToRemove) { - _uiManager.viewRegistry[view.reactTag] = view; - } -} - -@end diff --git a/packages/rn-tester/RNTesterUnitTests/RCTURLUtilsTests.m b/packages/rn-tester/RNTesterUnitTests/RCTURLUtilsTests.m deleted file mode 100644 index 318ed489038141..00000000000000 --- a/packages/rn-tester/RNTesterUnitTests/RCTURLUtilsTests.m +++ /dev/null @@ -1,103 +0,0 @@ -/* - * 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 - -#import - -@interface RCTURLUtilsTests : XCTestCase - -@end - -@implementation RCTURLUtilsTests - -- (void)testGetQueryParam -{ - NSURL *URL = [NSURL URLWithString:@"http://example.com?foo=bar&bar=foo"]; - NSString *foo = RCTGetURLQueryParam(URL, @"foo"); - NSString *bar = RCTGetURLQueryParam(URL, @"bar"); - XCTAssertEqualObjects(foo, @"bar"); - XCTAssertEqualObjects(bar, @"foo"); -} - -- (void)testGetEncodedParam -{ - NSURL *URL = [NSURL URLWithString:@"http://example.com?foo=You%20%26%20Me"]; - NSString *foo = RCTGetURLQueryParam(URL, @"foo"); - XCTAssertEqualObjects(foo, @"You & Me"); -} - -- (void)testQueryParamNotFound -{ - NSURL *URL = [NSURL URLWithString:@"http://example.com?foo=bar"]; - NSString *bar = RCTGetURLQueryParam(URL, @"bar"); - XCTAssertNil(bar); -} - -- (void)testDuplicateParamTakesLatter -{ - NSURL *URL = [NSURL URLWithString:@"http://example.com?foo=bar&foo=foo"]; - NSString *foo = RCTGetURLQueryParam(URL, @"foo"); - XCTAssertEqualObjects(foo, @"foo"); -} - -- (void)testNilURLGetQueryParam -{ - NSURL *URL = nil; - NSString *foo = RCTGetURLQueryParam(URL, @"foo"); - XCTAssertNil(foo); -} - -- (void)testReplaceParam -{ - NSURL *URL = [NSURL URLWithString:@"http://example.com?foo=bar&bar=foo"]; - NSURL *result = RCTURLByReplacingQueryParam(URL, @"foo", @"foo"); - XCTAssertEqualObjects(result.absoluteString, @"http://example.com?foo=foo&bar=foo"); -} - -- (void)testReplaceEncodedParam -{ - NSURL *URL = [NSURL URLWithString:@"http://example.com?foo=You%20%26%20Me"]; - NSURL *result = RCTURLByReplacingQueryParam(URL, @"foo", @"Me & You"); - XCTAssertEqualObjects(result.absoluteString, @"http://example.com?foo=Me%20%26%20You"); -} - -- (void)testAppendParam -{ - NSURL *URL = [NSURL URLWithString:@"http://example.com?bar=foo"]; - NSURL *result = RCTURLByReplacingQueryParam(URL, @"foo", @"bar"); - XCTAssertEqualObjects(result.absoluteString, @"http://example.com?bar=foo&foo=bar"); -} - -- (void)testRemoveParam -{ - NSURL *URL = [NSURL URLWithString:@"http://example.com?bar=foo&foo=bar"]; - NSURL *result = RCTURLByReplacingQueryParam(URL, @"bar", nil); - XCTAssertEqualObjects(result.absoluteString, @"http://example.com?foo=bar"); -} - -- (void)testNilURLAppendQueryParam -{ - NSURL *URL = nil; - NSURL *result = RCTURLByReplacingQueryParam(URL, @"foo", @"bar"); - XCTAssertNil(result); -} - -- (void)testIsLocalAssetsURLParam -{ - NSString *libraryAssetsPath = [RCTLibraryPath() stringByAppendingPathComponent:@"assets/foo.png"]; - NSURL *libraryAssetsURL = [NSURL fileURLWithPath:libraryAssetsPath]; - XCTAssertTrue(RCTIsLocalAssetURL(libraryAssetsURL)); - NSString *bundleAssetsPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"assets/foo.png"]; - NSURL *bundleAssetsURL = [NSURL fileURLWithPath:bundleAssetsPath]; - XCTAssertTrue(RCTIsLocalAssetURL(bundleAssetsURL)); - NSString *otherAssetsPath = @"/assets/foo.png"; - NSURL *otherAssetsURL = [NSURL fileURLWithPath:otherAssetsPath]; - XCTAssertFalse(RCTIsLocalAssetURL(otherAssetsURL)); -} - -@end diff --git a/packages/rn-tester/RNTesterUnitTests/RCTUnicodeDecodeTests.m b/packages/rn-tester/RNTesterUnitTests/RCTUnicodeDecodeTests.m deleted file mode 100644 index 492a63e7d58da0..00000000000000 --- a/packages/rn-tester/RNTesterUnitTests/RCTUnicodeDecodeTests.m +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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 - -#import - -static NSString *const niqqudStringB64 = - @"15HWsNa816jWtdeQ16nWtNeB15nXqiwg15HWuNa816jWuNeQINeQ1rHXnNa515TWtNeZ150sINeQ1rXXqiDXlNa316nWuNa814HXnta315nWtNedLCDXldaw15DWtdeqINeU1rjXkNa416jWttelLg=="; - -@interface RCTNetworking () - -+ (NSString *)decodeTextData:(NSData *)data - fromResponse:(NSURLResponse *)response - withCarryData:(NSMutableData *)inputCarryData; - -@end - -@interface RCTUnicodeDecodeTests : XCTestCase - -@end - -@implementation RCTUnicodeDecodeTests - -- (void)runTestForString:(NSString *)unicodeString usingEncoding:(NSString *)encodingName cutAt:(NSUInteger)cutPoint -{ - CFStringEncoding cfEncoding = CFStringConvertIANACharSetNameToEncoding((CFStringRef)encodingName); - NSStringEncoding encoding = CFStringConvertEncodingToNSStringEncoding(cfEncoding); - - NSData *unicodeBytes = [unicodeString dataUsingEncoding:encoding]; - - NSURLResponse *fakeResponse = [[NSHTTPURLResponse alloc] - initWithURL:[NSURL URLWithString:@"testurl://"] - statusCode:200 - HTTPVersion:@"1.1" - headerFields:@{@"content-type" : [NSString stringWithFormat:@"text/plain; charset=%@", encodingName]}]; - XCTAssert([fakeResponse.textEncodingName isEqualToString:encodingName]); - - NSMutableData *carryStorage = [NSMutableData new]; - NSMutableString *parsedString = [NSMutableString new]; - - [parsedString appendString:[RCTNetworking decodeTextData:[unicodeBytes subdataWithRange:NSMakeRange(0, cutPoint)] - fromResponse:fakeResponse - withCarryData:carryStorage] - ?: @""]; - - [parsedString - appendString:[RCTNetworking - decodeTextData:[unicodeBytes - subdataWithRange:NSMakeRange(cutPoint, unicodeBytes.length - cutPoint)] - fromResponse:fakeResponse - withCarryData:carryStorage] - ?: @""]; - - XCTAssert(carryStorage.length == 0); - XCTAssert([parsedString isEqualToString:unicodeString]); -} - -- (void)testNiqqud -{ - NSString *unicodeString = [[NSString alloc] - initWithData:[[NSData alloc] initWithBase64EncodedString:niqqudStringB64 options:(NSDataBase64DecodingOptions)0] - encoding:NSUTF8StringEncoding]; - - [self runTestForString:unicodeString usingEncoding:@"utf-8" cutAt:25]; -} - -- (void)testEmojis -{ - NSString *unicodeString = @"\U0001F602\U0001F602"; - - [self runTestForString:unicodeString usingEncoding:@"utf-8" cutAt:7]; -} - -@end diff --git a/packages/rn-tester/RNTesterUnitTests/RCTUtilsTests.m b/packages/rn-tester/RNTesterUnitTests/RCTUtilsTests.m deleted file mode 100644 index a647a4450b8cd2..00000000000000 --- a/packages/rn-tester/RNTesterUnitTests/RCTUtilsTests.m +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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 - -#import -#import - -static NSString *RCTLogsError(void (^block)(void)) -{ - __block NSString *loggedMessage = @""; - __block BOOL loggedError = NO; - RCTPerformBlockWithLogFunction( - block, - ^(RCTLogLevel level, - __unused RCTLogSource source, - __unused NSString *fileName, - __unused NSNumber *lineNumber, - NSString *message) { - loggedError = (level == RCTLogLevelError); - loggedMessage = message; - }); - if (loggedError) { - return loggedMessage; - } - return nil; -} - -@interface RCTUtilsTests : XCTestCase - -@end - -@implementation RCTUtilsTests - -- (void)testRCTHumanReadableType -{ - XCTAssertEqualObjects(RCTHumanReadableType(@"str"), @"string"); - XCTAssertEqualObjects(RCTHumanReadableType([NSNumber numberWithInt:4]), @"number"); - - // If we could detect that this was definitely a boolean and not a number that would be ideal - // That seems difficult in ObjC though - XCTAssertEqualObjects(RCTHumanReadableType(@(YES)), @"boolean or number"); - XCTAssertEqualObjects(RCTHumanReadableType(@(NO)), @"boolean or number"); - // These ideally would just say number - XCTAssertEqualObjects(RCTHumanReadableType([NSNumber numberWithInt:0]), @"boolean or number"); - XCTAssertEqualObjects(RCTHumanReadableType([NSNumber numberWithInt:1]), @"boolean or number"); -} - -- (void)testRCTValidateTypeOfViewCommandArgument -{ - XCTAssertEqualObjects( - RCTLogsError(^{ - RCTValidateTypeOfViewCommandArgument(@"str", [NSNumber class], @"number", @"ScrollView", @"scrollTo", @"2nd"); - }), - @"ScrollView command scrollTo received 2nd argument of type string, expected number."); - - XCTAssertEqualObjects( - RCTLogsError(^{ - RCTValidateTypeOfViewCommandArgument(@"str", [NSString class], @"string", @"ScrollView", @"scrollTo", @"1st"); - }), - nil); -} - -@end diff --git a/packages/rn-tester/RNTesterUnitTests/RCTViewTests.m b/packages/rn-tester/RNTesterUnitTests/RCTViewTests.m deleted file mode 100644 index 0bc4e206f4b63f..00000000000000 --- a/packages/rn-tester/RNTesterUnitTests/RCTViewTests.m +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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 -#import "OCMock/OCMock.h" - -#import -#import -#import -#import -#import - -RCT_MOCK_REF(RCTView, RCTContentInsets); - -UIEdgeInsets gContentInsets; -static UIEdgeInsets RCTContentInsetsMock(__unused UIView *view) -{ - return gContentInsets; -} - -@interface RCTViewTests : XCTestCase -@end - -@implementation RCTViewTests - -- (void)testAutoAdjustInsetsUpdateOffsetNo -{ - RCT_MOCK_SET(RCTView, RCTContentInsets, RCTContentInsetsMock); - - RCTScrollView *parentView = OCMClassMock([RCTScrollView class]); - OCMStub([parentView contentInset]).andReturn(UIEdgeInsetsMake(1, 1, 1, 1)); - OCMStub([parentView automaticallyAdjustContentInsets]).andReturn(YES); - UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:CGRectZero]; - - gContentInsets = UIEdgeInsetsMake(1, 2, 3, 4); - [RCTView autoAdjustInsetsForView:parentView withScrollView:scrollView updateOffset:NO]; - - XCTAssertTrue(UIEdgeInsetsEqualToEdgeInsets(scrollView.contentInset, UIEdgeInsetsMake(2, 3, 4, 5))); - XCTAssertTrue(UIEdgeInsetsEqualToEdgeInsets(scrollView.verticalScrollIndicatorInsets, UIEdgeInsetsMake(2, 3, 4, 5))); - - RCT_MOCK_RESET(RCTView, RCTContentInsets); -} - -@end diff --git a/packages/rn-tester/RNTesterUnitTests/RNTesterUnitTestsBundle.js b/packages/rn-tester/RNTesterUnitTests/RNTesterUnitTestsBundle.js deleted file mode 100644 index 2121f025ff2337..00000000000000 --- a/packages/rn-tester/RNTesterUnitTests/RNTesterUnitTestsBundle.js +++ /dev/null @@ -1,17 +0,0 @@ -/** - * 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. - * - * @format - */ - -'use strict'; - -// eslint-disable-next-line no-unused-vars -const __fbBatchedBridge = { - flushedQueue: function () { - return null; - }, -}; diff --git a/scripts/objc-test.sh b/scripts/objc-test.sh deleted file mode 100755 index 207f71dc0bb6e4..00000000000000 --- a/scripts/objc-test.sh +++ /dev/null @@ -1,195 +0,0 @@ -#!/bin/bash -# 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. - -# Script used to run iOS tests. -# If no arguments are passed to the script, it will only compile -# the RNTester. -# If the script is called with a single argument "test", we'll -# run the RNTester unit and integration tests -# ./objc-test.sh test - -SCRIPTS=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) -ROOT=$(dirname "$SCRIPTS") - -SKIPPED_TESTS=() -# TODO: T60408036 This test crashes iOS 13 for bad access, please investigate -# and re-enable. See https://gist.github.com/0xced/56035d2f57254cf518b5. -SKIPPED_TESTS+=("-skip-testing:RNTesterUnitTests/RCTJSONTests/testNotUTF8Convertible") - -# Create cleanup handler -cleanup() { - EXIT=$? - set +e - - if [ $EXIT -ne 0 ]; - then - WATCHMAN_LOGS=/usr/local/Cellar/watchman/3.1/var/run/watchman/$USER.log - [ -f "$WATCHMAN_LOGS" ] && cat "$WATCHMAN_LOGS" - fi - # kill whatever is occupying port 8081 (packager) - lsof -i tcp:8081 | awk 'NR!=1 {print $2}' | xargs kill - # kill whatever is occupying port 5555 (web socket server) - lsof -i tcp:5555 | awk 'NR!=1 {print $2}' | xargs kill -} - -# Wait for the package to start -waitForPackager() { - local -i max_attempts=60 - local -i attempt_num=1 - - until curl -s http://localhost:8081/status | grep "packager-status:running" -q; do - if (( attempt_num == max_attempts )); then - echo "Packager did not respond in time. No more attempts left." - exit 1 - else - (( attempt_num++ )) - echo "Packager did not respond. Retrying for attempt number $attempt_num..." - sleep 1 - fi - done - - echo "Packager is ready!" -} - -waitForWebSocketServer() { - local -i max_attempts=60 - local -i attempt_num=1 - - until curl -s http://localhost:5555 | grep "Upgrade Required" -q; do - if (( attempt_num == max_attempts )); then - echo "WebSocket Server did not respond in time. No more attempts left." - exit 1 - else - (( attempt_num++ )) - echo "WebSocket Server did not respond. Retrying for attempt number $attempt_num..." - sleep 1 - fi - done - - echo "WebSocket Server is ready!" -} - -runTests() { - # shellcheck disable=SC1091 - source "$ROOT/scripts/.tests.env" - xcodebuild build test \ - -workspace RNTesterPods.xcworkspace \ - -scheme RNTester \ - -sdk iphonesimulator \ - -destination "platform=iOS Simulator,name=$IOS_DEVICE,OS=$IOS_TARGET_OS" \ - "${SKIPPED_TESTS[@]}" -} - -buildForTesting() { - # shellcheck disable=SC1091 - source "$ROOT/scripts/.tests.env" - xcodebuild build-for-testing \ - -workspace RNTesterPods.xcworkspace \ - -scheme RNTester \ - -sdk iphonesimulator -} - -runTestsOnly() { - # shellcheck disable=SC1091 - source "$ROOT/scripts/.tests.env" - echo "[Testing] Running tests on $IOS_DEVICE for OS $IOS_TARGET_OS" - xcodebuild test \ - -workspace RNTesterPods.xcworkspace \ - -scheme RNTester \ - -sdk iphonesimulator \ - -destination "platform=iOS Simulator,name=$IOS_DEVICE,OS=$IOS_TARGET_OS" \ - "${SKIPPED_TESTS[@]}" -} - -buildProject() { - xcodebuild build \ - -workspace RNTesterPods.xcworkspace \ - -scheme RNTester \ - -sdk iphonesimulator -} - -xcbeautifyFormat() { - if [ "$CI" ]; then - # CI expects JUnit reports to be available here - REPORTS_DIR="$HOME/react-native/reports/junit" - else - THIS_DIR=$(cd -P "$(dirname "$(realpath "${BASH_SOURCE[0]}" || echo "${BASH_SOURCE[0]}")")" && pwd) - - # Write reports to the react-native root dir - REPORTS_DIR="$THIS_DIR/../build/reports" - fi - - xcbeautify --report junit --report-path "$REPORTS_DIR/ios/results.xml" -} - -preloadBundlesRNIntegrationTests() { - # Preload IntegrationTests bundles (packages/rn-tester/) - curl -s 'http://localhost:8081/IntegrationTests/IntegrationTestsApp.bundle?platform=ios&dev=true' -o /dev/null -} - -preloadBundlesRNTester() { - # Preload RNTesterApp bundles (packages/rn-tester/) - curl -s 'http://localhost:8081/js/RNTesterApp.ios.bundle?platform=ios&dev=true' -o /dev/null - curl -s 'http://localhost:8081/js/RNTesterApp.ios.bundle?platform=ios&dev=true&minify=false' -o /dev/null -} - -main() { - cd "$ROOT/packages/rn-tester" || exit - - # If first argument is "test", actually start the packager and run tests. - # Otherwise, just build RNTester and exit - if [ "$1" = "test" ]; then - - # Start the WebSocket test server - echo "Launch WebSocket Server" - sh "./IntegrationTests/launchWebSocketServer.sh" & - waitForWebSocketServer - - # Start the packager - yarn start --max-workers=1 || echo "Can't start packager automatically" & - waitForPackager - preloadBundlesRNTester - preloadBundlesRNIntegrationTests - - buildForTesting - - # Build and run tests. - RESULT=-1 - MAX_RETRY=3 - for ((i=1; i<=MAX_RETRY; i++)) - do - echo "Attempt #$i of running tests..." - if [ -x "$(command -v xcbeautify)" ]; then - runTests | xcbeautifyFormat && exit "${PIPESTATUS[0]}" - RESULT="$?" - else - echo 'Warning: xcbeautify is not installed. Install xcbeautify to generate JUnit reports.' - runTests - RESULT="$?" - fi - - if [[ "$RESULT" == 0 ]]; then - # Successful tests! - echo "Test completed successfully!" - exit 0 - fi - done - - echo "Test Failed with code $RESULT!" - exit $RESULT - - else - # Build without running tests. - if [ -x "$(command -v xcbeautify)" ]; then - buildProject | xcbeautifyFormat && exit "${PIPESTATUS[0]}" - else - buildProject - fi - fi -} - -trap cleanup EXIT -main "$@"