├── .npmignore ├── ios ├── e2eTests.app │ ├── PkgInfo │ ├── e2eTests │ ├── Info.plist │ ├── Base.lproj │ │ └── LaunchScreen.nib │ ├── Frameworks │ │ ├── XCTest.framework │ │ │ ├── XCTest │ │ │ ├── Info.plist │ │ │ ├── Modules │ │ │ │ └── module.modulemap │ │ │ ├── en.lproj │ │ │ │ └── InfoPlist.strings │ │ │ ├── XPCServices │ │ │ │ ├── xctestSymbolicator.xpc │ │ │ │ │ ├── Info.plist │ │ │ │ │ ├── xctestSymbolicator │ │ │ │ │ ├── version.plist │ │ │ │ │ └── _CodeSignature │ │ │ │ │ │ └── CodeResources │ │ │ │ └── XCUIRecorderService.xpc │ │ │ │ │ ├── Info.plist │ │ │ │ │ ├── XCUIRecorderService │ │ │ │ │ ├── version.plist │ │ │ │ │ └── _CodeSignature │ │ │ │ │ └── CodeResources │ │ │ ├── version.plist │ │ │ └── Headers │ │ │ │ ├── XCTestErrors.h │ │ │ │ ├── XCUISiriService.h │ │ │ │ ├── XCTNSPredicateExpectation.h │ │ │ │ ├── XCUIRemote.h │ │ │ │ ├── XCUIDevice.h │ │ │ │ ├── XCTestCaseRun.h │ │ │ │ ├── XCTestSuiteRun.h │ │ │ │ ├── XCTDarwinNotificationExpectation.h │ │ │ │ ├── XCTestObservationCenter.h │ │ │ │ ├── XCTestLog.h │ │ │ │ ├── XCUIApplication.h │ │ │ │ ├── XCTestProbe.h │ │ │ │ ├── XCTNSNotificationExpectation.h │ │ │ │ ├── XCTestObserver.h │ │ │ │ ├── XCTestDefines.h │ │ │ │ ├── XCUIElementAttributes.h │ │ │ │ ├── XCTestExpectation.h │ │ │ │ ├── XCUIKeyboardKeys.h │ │ │ │ ├── XCUICoordinate.h │ │ │ │ ├── XCTest.h │ │ │ │ ├── XCUIElementTypes.h │ │ │ │ ├── XCTestSuite.h │ │ │ │ ├── XCAbstractTest.h │ │ │ │ ├── XCTKVOExpectation.h │ │ │ │ ├── XCUIElementQuery.h │ │ │ │ ├── XCTestObservation.h │ │ │ │ └── XCUIElementTypeQueryProvider.h │ │ └── IDEBundleInjection.framework │ │ │ ├── Info.plist │ │ │ ├── IDEBundleInjection │ │ │ ├── version.plist │ │ │ └── _CodeSignature │ │ │ └── CodeResources │ └── PlugIns │ │ ├── e2eTestsTests.xctest │ │ ├── Info.plist │ │ ├── e2eTestsTests │ │ └── _CodeSignature │ │ │ └── CodeResources │ │ └── e2eTestsTests.xctest.dSYM │ │ └── Contents │ │ ├── Resources │ │ └── DWARF │ │ │ └── e2eTestsTests │ │ └── Info.plist ├── e2eTests │ ├── AppDelegate.h │ ├── main.m │ ├── Images.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── AppDelegate.m │ ├── Info.plist │ └── Base.lproj │ │ └── LaunchScreen.xib ├── e2eTestsTests │ ├── Info.plist │ └── e2eTestsTests.m └── e2eTests.xcodeproj │ └── xcshareddata │ └── xcschemes │ └── e2eTests.xcscheme ├── .gitattributes ├── _config.yml ├── index.ios.js ├── index.web.js ├── .babelrc ├── index.android.js ├── packages ├── server │ ├── index.html │ ├── start.js │ ├── index.test.js │ └── index.js ├── app │ └── src │ │ ├── __mocks__ │ │ └── componentLoader.js │ │ ├── components │ │ ├── __mocks__ │ │ │ └── fructoseComponent.js │ │ ├── navigation │ │ │ ├── back-icon.png │ │ │ ├── forward-icon.png │ │ │ ├── parentNavigationItem.test.js │ │ │ ├── __snapshots__ │ │ │ │ ├── navigation.test.js.snap │ │ │ │ ├── parentNavigationItem.test.js.snap │ │ │ │ └── navigationHeader.test.js.snap │ │ │ ├── navigationHeader.test.js │ │ │ ├── parentNavigationItem.js │ │ │ ├── navigationHeader.js │ │ │ ├── navigation.test.js │ │ │ └── navigation.js │ │ ├── __snapshots__ │ │ │ ├── app.test.js.snap │ │ │ └── errorBoundaryComponent.test.js.snap │ │ ├── app.js │ │ ├── errorBoundaryComponent.js │ │ ├── getNavigationScreens.js │ │ ├── app.test.js │ │ ├── errorViewComponent.js │ │ ├── fructoseComponentWrapper.js │ │ ├── loadingScreen.js │ │ └── errorBoundaryComponent.test.js │ │ ├── index.js │ │ ├── componentLoader.js │ │ └── componentLoader.test.js ├── test-helpers │ ├── src │ │ ├── index.js │ │ ├── index.test.js │ │ ├── didWebStart.js │ │ ├── setup.js │ │ └── bin │ │ │ ├── github-comment-manager.js │ │ │ ├── run.js │ │ │ └── github-comment-manager.test.js │ └── bin │ │ └── createTunnel.js ├── client │ ├── index.js │ ├── client.js │ └── client.test.js ├── web │ ├── index.ejs │ ├── webpack.config.js │ └── bin │ │ └── start.js └── common │ └── logger.js ├── android ├── settings.gradle ├── app │ ├── fructose.keystore │ ├── src │ │ └── main │ │ │ ├── res │ │ │ ├── values │ │ │ │ ├── strings.xml │ │ │ │ └── styles.xml │ │ │ ├── mipmap-hdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ │ └── ic_launcher.png │ │ │ └── mipmap-xxhdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── java │ │ │ └── com │ │ │ │ └── e2etests │ │ │ │ ├── MainActivity.java │ │ │ │ └── MainApplication.java │ │ │ └── AndroidManifest.xml │ ├── BUCK │ └── proguard-rules.pro ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── keystores │ ├── debug.keystore.properties │ └── BUCK ├── build.gradle ├── gradle.properties └── gradlew.bat ├── e2eTests ├── app.json ├── fructose │ ├── head.html │ ├── webpack.config.js │ ├── index.ios.js │ ├── index.android.js │ ├── index.web.js │ ├── vendor.webpack.config.js │ └── setup.android.sauce.js ├── scripts │ ├── web-tests.sh │ ├── ios-tests.sh │ ├── android-saucelabs-tests.sh │ └── android-tests.sh ├── example │ ├── setup.native.hooks.js │ ├── android.test.js │ ├── ios.test.js │ ├── web.test.js │ ├── component-pages.showcase.js │ └── component-primitives.showcase.js └── rn-cli.config.js ├── app.json ├── index.js ├── scripts ├── install-all-deps.sh ├── tests.sh └── ci.sh ├── setup.js ├── .buckconfig ├── .eslintignore ├── lerna.json ├── __mocks__ └── pixelmatch.js ├── .eslintrc.json ├── .gitignore ├── LICENSE ├── CONTRIBUTING.md └── package.json /.npmignore: -------------------------------------------------------------------------------- 1 | e2eTests/** -------------------------------------------------------------------------------- /ios/e2eTests.app/PkgInfo: -------------------------------------------------------------------------------- 1 | APPL???? -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.pbxproj -text 2 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-midnight -------------------------------------------------------------------------------- /index.ios.js: -------------------------------------------------------------------------------- 1 | require("./e2eTests/fructose/index.ios.js"); 2 | -------------------------------------------------------------------------------- /index.web.js: -------------------------------------------------------------------------------- 1 | require("./e2eTests/fructose/index.web.js"); 2 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "react-native" 4 | ] 5 | } -------------------------------------------------------------------------------- /index.android.js: -------------------------------------------------------------------------------- 1 | require("./e2eTests/fructose/index.android.js"); 2 | -------------------------------------------------------------------------------- /packages/server/index.html: -------------------------------------------------------------------------------- 1 |

FRUCTOSE SERVER

-------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'e2eTests' 2 | 3 | include ':app' 4 | -------------------------------------------------------------------------------- /e2eTests/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "e2eTests", 3 | "displayName": "e2eTests" 4 | } -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rncomponentapp", 3 | "displayName": "rncomponentapp" 4 | } -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | import app from "./packages/app/src/index"; 2 | 3 | export default app; 4 | -------------------------------------------------------------------------------- /packages/app/src/__mocks__/componentLoader.js: -------------------------------------------------------------------------------- 1 | export default () => "componentsLoaded"; 2 | -------------------------------------------------------------------------------- /scripts/install-all-deps.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | yarn 4 | cd e2eTests 5 | rm -rf node_modules 6 | yarn -------------------------------------------------------------------------------- /setup.js: -------------------------------------------------------------------------------- 1 | const setup = require("./packages/test-helpers/lib/index"); 2 | 3 | module.exports = setup; -------------------------------------------------------------------------------- /e2eTests/fructose/head.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ios/e2eTests.app/e2eTests: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewsUKArchive/fructose/HEAD/ios/e2eTests.app/e2eTests -------------------------------------------------------------------------------- /packages/app/src/components/__mocks__/fructoseComponent.js: -------------------------------------------------------------------------------- 1 | export default () => "FructoseComponent"; 2 | -------------------------------------------------------------------------------- /ios/e2eTests.app/Info.plist: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewsUKArchive/fructose/HEAD/ios/e2eTests.app/Info.plist -------------------------------------------------------------------------------- /packages/server/start.js: -------------------------------------------------------------------------------- 1 | const Server = require("./index").FructoseServer; 2 | 3 | new Server(7811).start(); 4 | -------------------------------------------------------------------------------- /android/app/fructose.keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewsUKArchive/fructose/HEAD/android/app/fructose.keystore -------------------------------------------------------------------------------- /android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | e2eTests 3 | 4 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewsUKArchive/fructose/HEAD/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /ios/e2eTests.app/Base.lproj/LaunchScreen.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewsUKArchive/fructose/HEAD/ios/e2eTests.app/Base.lproj/LaunchScreen.nib -------------------------------------------------------------------------------- /.buckconfig: -------------------------------------------------------------------------------- 1 | 2 | [android] 3 | target = Google Inc.:Google APIs:23 4 | 5 | [maven_repositories] 6 | central = https://repo1.maven.org/maven2 7 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewsUKArchive/fructose/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewsUKArchive/fructose/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /ios/e2eTests.app/Frameworks/XCTest.framework/XCTest: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewsUKArchive/fructose/HEAD/ios/e2eTests.app/Frameworks/XCTest.framework/XCTest -------------------------------------------------------------------------------- /packages/app/src/components/navigation/back-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewsUKArchive/fructose/HEAD/packages/app/src/components/navigation/back-icon.png -------------------------------------------------------------------------------- /packages/test-helpers/src/index.js: -------------------------------------------------------------------------------- 1 | import hooks from "./setup"; 2 | 3 | const fructose = {}; 4 | fructose.hooks = hooks; 5 | 6 | export default fructose; 7 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewsUKArchive/fructose/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewsUKArchive/fructose/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/keystores/debug.keystore.properties: -------------------------------------------------------------------------------- 1 | key.store=debug.keystore 2 | key.alias=androiddebugkey 3 | key.store.password=android 4 | key.alias.password=android 5 | -------------------------------------------------------------------------------- /ios/e2eTests.app/Frameworks/XCTest.framework/Info.plist: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewsUKArchive/fructose/HEAD/ios/e2eTests.app/Frameworks/XCTest.framework/Info.plist -------------------------------------------------------------------------------- /packages/app/src/components/navigation/forward-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewsUKArchive/fructose/HEAD/packages/app/src/components/navigation/forward-icon.png -------------------------------------------------------------------------------- /ios/e2eTests.app/PlugIns/e2eTestsTests.xctest/Info.plist: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewsUKArchive/fructose/HEAD/ios/e2eTests.app/PlugIns/e2eTestsTests.xctest/Info.plist -------------------------------------------------------------------------------- /ios/e2eTests.app/PlugIns/e2eTestsTests.xctest/e2eTestsTests: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewsUKArchive/fructose/HEAD/ios/e2eTests.app/PlugIns/e2eTestsTests.xctest/e2eTestsTests -------------------------------------------------------------------------------- /ios/e2eTests.app/Frameworks/XCTest.framework/Modules/module.modulemap: -------------------------------------------------------------------------------- 1 | framework module XCTest { 2 | umbrella header "XCTest.h" 3 | requires objc 4 | export * 5 | } 6 | -------------------------------------------------------------------------------- /packages/app/src/components/__snapshots__/app.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`App Renders the root stack 1`] = ``; 4 | -------------------------------------------------------------------------------- /ios/e2eTests.app/Frameworks/IDEBundleInjection.framework/Info.plist: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewsUKArchive/fructose/HEAD/ios/e2eTests.app/Frameworks/IDEBundleInjection.framework/Info.plist -------------------------------------------------------------------------------- /ios/e2eTests.app/Frameworks/XCTest.framework/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewsUKArchive/fructose/HEAD/ios/e2eTests.app/Frameworks/XCTest.framework/en.lproj/InfoPlist.strings -------------------------------------------------------------------------------- /android/keystores/BUCK: -------------------------------------------------------------------------------- 1 | keystore( 2 | name = "debug", 3 | properties = "debug.keystore.properties", 4 | store = "debug.keystore", 5 | visibility = [ 6 | "PUBLIC", 7 | ], 8 | ) 9 | -------------------------------------------------------------------------------- /ios/e2eTests.app/Frameworks/IDEBundleInjection.framework/IDEBundleInjection: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewsUKArchive/fructose/HEAD/ios/e2eTests.app/Frameworks/IDEBundleInjection.framework/IDEBundleInjection -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | **/node_modules/* 2 | **/coverage/* 3 | **/lib/* 4 | packages/test-helpers/**/*.test.js 5 | **/*.tape.js 6 | **/.fructose/components.js 7 | **/.fructose/components.test.js 8 | **/e2eTests/** 9 | 10 | **/dist/* -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "lerna": "2.0.0-rc.5", 3 | "packages": [ 4 | "packages/app", 5 | "packages/server", 6 | "packages/client", 7 | "packages/test-helpers", 8 | "packages/fructose" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /ios/e2eTests.app/Frameworks/XCTest.framework/XPCServices/xctestSymbolicator.xpc/Info.plist: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewsUKArchive/fructose/HEAD/ios/e2eTests.app/Frameworks/XCTest.framework/XPCServices/xctestSymbolicator.xpc/Info.plist -------------------------------------------------------------------------------- /ios/e2eTests.app/PlugIns/e2eTestsTests.xctest.dSYM/Contents/Resources/DWARF/e2eTestsTests: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewsUKArchive/fructose/HEAD/ios/e2eTests.app/PlugIns/e2eTestsTests.xctest.dSYM/Contents/Resources/DWARF/e2eTestsTests -------------------------------------------------------------------------------- /ios/e2eTests.app/Frameworks/XCTest.framework/XPCServices/XCUIRecorderService.xpc/Info.plist: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewsUKArchive/fructose/HEAD/ios/e2eTests.app/Frameworks/XCTest.framework/XPCServices/XCUIRecorderService.xpc/Info.plist -------------------------------------------------------------------------------- /ios/e2eTests.app/Frameworks/XCTest.framework/XPCServices/XCUIRecorderService.xpc/XCUIRecorderService: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewsUKArchive/fructose/HEAD/ios/e2eTests.app/Frameworks/XCTest.framework/XPCServices/XCUIRecorderService.xpc/XCUIRecorderService -------------------------------------------------------------------------------- /ios/e2eTests.app/Frameworks/XCTest.framework/XPCServices/xctestSymbolicator.xpc/xctestSymbolicator: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewsUKArchive/fructose/HEAD/ios/e2eTests.app/Frameworks/XCTest.framework/XPCServices/xctestSymbolicator.xpc/xctestSymbolicator -------------------------------------------------------------------------------- /__mocks__/pixelmatch.js: -------------------------------------------------------------------------------- 1 | /* globals jest */ 2 | 3 | let mockPixelMatch = (data1, data2) => { 4 | if (data1.equals(data2)) { 5 | return 0; 6 | } 7 | return 1; 8 | }; 9 | 10 | mockPixelMatch = jest.fn(); 11 | module.exports = mockPixelMatch; 12 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip 6 | -------------------------------------------------------------------------------- /e2eTests/fructose/webpack.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable global-require */ 2 | const path = require("path"); 3 | 4 | module.exports = { 5 | entry: [path.join(__dirname, "./index.web.js")], 6 | node: { 7 | fs: "empty", 8 | net: "empty" 9 | } 10 | }; 11 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "airbnb", 4 | "prettier", 5 | "prettier/react" 6 | ], 7 | "rules": { 8 | "react/jsx-filename-extension": [1, { "extensions": [".js"] }], 9 | "import/extensions": "off" 10 | }, 11 | "root": true, 12 | "env": { 13 | "jest": true 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /e2eTests/fructose/index.ios.js: -------------------------------------------------------------------------------- 1 | import { AppRegistry } from "react-native"; 2 | import fructose from "../../packages/app/src"; 3 | import { getStories } from "./components"; // eslint-disable-line import/no-unresolved 4 | 5 | AppRegistry.registerComponent("e2eTests", () => 6 | fructose(getStories, { platform: "native" }) 7 | ); 8 | -------------------------------------------------------------------------------- /e2eTests/fructose/index.android.js: -------------------------------------------------------------------------------- 1 | import { AppRegistry } from "react-native"; 2 | import fructose from "../../packages/app/src"; 3 | import { getStories } from "./components"; // eslint-disable-line import/no-unresolved 4 | 5 | AppRegistry.registerComponent("e2eTests", () => 6 | fructose(getStories, { platform: "native" }) 7 | ); 8 | -------------------------------------------------------------------------------- /e2eTests/scripts/web-tests.sh: -------------------------------------------------------------------------------- 1 | ./node_modules/.bin/rnscl --searchDir ./e2eTests/ --pattern 'example/*.showcase.js' --outputFile e2eTests/fructose/components.js 2 | node "./packages/web/bin/start" --build-dir $(pwd)/e2eTests/fructose & 3 | WEB_PID=$! 4 | ./node_modules/.bin/jest ./e2eTests/example/web.test.js --verbose --forceExit 5 | TESTS_EXIT_CODE=$? 6 | kill -9 $WEB_PID 7 | exit $TESTS_EXIT_CODE -------------------------------------------------------------------------------- /packages/test-helpers/src/index.test.js: -------------------------------------------------------------------------------- 1 | test("index exports function as default", async () => { 2 | const fructose = require("./index").default; 3 | expect(typeof fructose.hooks.mobile.setup).toBe("function"); 4 | expect(typeof fructose.hooks.mobile.cleanup).toBe("function"); 5 | expect(typeof fructose.hooks.web.setup).toBe("function"); 6 | expect(typeof fructose.hooks.web.cleanup).toBe("function"); 7 | }); 8 | -------------------------------------------------------------------------------- /packages/client/index.js: -------------------------------------------------------------------------------- 1 | const SocketClient = require("socket.io-client"); 2 | const FructoseClient = require("./client"); 3 | 4 | const config = { 5 | transports: ["websocket"], 6 | query: { 7 | clientType: "tests" 8 | } 9 | }; 10 | 11 | const sc = port => new SocketClient(`http://localhost:${port || 7811}`, config); 12 | const fc = port => new FructoseClient(sc(port)); 13 | 14 | module.exports = fc; 15 | -------------------------------------------------------------------------------- /e2eTests/example/setup.native.hooks.js: -------------------------------------------------------------------------------- 1 | /* globals jasmine */ 2 | import fructose from "../../setup"; 3 | import io from "socket.io-client"; 4 | 5 | export const setup = async () => { 6 | jasmine.DEFAULT_TIMEOUT_INTERVAL = 25000; 7 | const fructoseClient = await fructose.hooks.mobile.setup(); 8 | return fructoseClient; 9 | }; 10 | 11 | export const teardown = async () => { 12 | await fructose.hooks.mobile.cleanup(); 13 | }; 14 | -------------------------------------------------------------------------------- /e2eTests/rn-cli.config.js: -------------------------------------------------------------------------------- 1 | const blacklist = require("metro-bundler/src/blacklist"); 2 | 3 | module.exports = { 4 | getBlacklistRE() { 5 | return blacklist([ 6 | /\/node_modules\/jest-haste-map\/node_modules\/.*/, 7 | /\/node_modules\/react-native\/node_modules\/fb-watchman\/.*/, 8 | /\/node_modules\/@times-components\/fructose\/node_modules\/react-native\/.*/, 9 | /\..\/.*/ 10 | ]); 11 | } 12 | }; 13 | -------------------------------------------------------------------------------- /scripts/tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | yarn --npm-client=yarn --concurrency=1 4 | 5 | if yarn test:unit ; then 6 | echo "UNIT TESTS PASSED" 7 | else 8 | echo "UNIT TESTS FAILED" 9 | exit 1 10 | fi 11 | 12 | if yarn e2e:test:web ; then 13 | echo "WEB TESTS PASSED" 14 | else 15 | echo "WEB TESTS FAILED" 16 | exit 1 17 | fi 18 | 19 | if yarn e2e:test:ios ; then 20 | echo "IOS TESTS PASSED" 21 | else 22 | echo "IOS TESTS FAILED" 23 | exit 1 24 | fi 25 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/e2etests/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.e2etests; 2 | 3 | import com.facebook.react.ReactActivity; 4 | 5 | public class MainActivity extends ReactActivity { 6 | 7 | /** 8 | * Returns the name of the main component registered from JavaScript. 9 | * This is used to schedule rendering of the component. 10 | */ 11 | @Override 12 | protected String getMainComponentName() { 13 | return "e2eTests"; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /e2eTests/fructose/index.web.js: -------------------------------------------------------------------------------- 1 | /* globals document */ 2 | 3 | import { AppRegistry, Text } from "react-native"; 4 | import fructose from "../../packages/app/src"; 5 | import { getStories } from "./components"; // eslint-disable-line import/no-unresolved 6 | 7 | AppRegistry.registerComponent("e2eTests", () => 8 | fructose(getStories, { platform: "web" }) 9 | ); 10 | AppRegistry.runApplication("e2eTests", { 11 | rootTag: document.getElementById("react-root") 12 | }); 13 | -------------------------------------------------------------------------------- /packages/web/index.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | React Native Web 7 | 8 | 9 | 14 | 15 | 16 |
17 | 18 | 19 | -------------------------------------------------------------------------------- /scripts/ci.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | if yarn test:unit ; then 5 | echo "UNIT TESTS PASSED" 6 | else 7 | echo "UNIT TESTS FAILED" 8 | cd ../.. 9 | exit 1 10 | fi 11 | 12 | cd e2eTests 13 | if yarn test:web ; then 14 | echo "E2E WEB TESTS PASSED" 15 | else 16 | echo "E2E WEB TESTS FAILED" 17 | cd ../.. 18 | exit 1 19 | fi 20 | 21 | if yarn test:ios ; then 22 | echo "E2E IOS TESTS PASSED" 23 | else 24 | echo "E2E IOS TESTS FAILED" 25 | cd ../.. 26 | exit 1 27 | fi 28 | -------------------------------------------------------------------------------- /e2eTests/scripts/ios-tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | xcrun simctl boot 'iPhone 7' 3 | export IPHONE=$! 4 | ./node_modules/.bin/rnscl --searchDir ./e2eTests/ --pattern 'example/*.showcase.js' --outputFile e2eTests/fructose/components.js 5 | ./node_modules/.bin/react-native start --resetCache & 6 | export PACKAGER=$! 7 | ./node_modules/.bin/react-native run-ios --no-packager 8 | LOGLEVEL=verbose node_modules/.bin/jest ./e2eTests/example/ios.test.js --verbose --forceExit 9 | 10 | kill $IPHONE 11 | kill $PACKAGER -------------------------------------------------------------------------------- /ios/e2eTests/AppDelegate.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import 11 | 12 | @interface AppDelegate : UIResponder 13 | 14 | @property (nonatomic, strong) UIWindow *window; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /e2eTests/scripts/android-saucelabs-tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | npx fructose-tunnel & 3 | yarn write-android-components 4 | pushd android 5 | ./gradlew clean 6 | ./gradlew assembleRelease 7 | popd 8 | curl -u $SAUCE_USERNAME:$SAUCE_KEY\ 9 | -X POST \ 10 | -H "Content-Type: application/octet-stream"\ 11 | https://saucelabs.com/rest/v1/storage/tnlweb/fructose-e2e.apk?overwrite=true\ 12 | --data-binary @${PWD}/android/app/build/outputs/apk/app-release.apk 13 | 14 | jest fructose/components.test.js --verbose --setupTestFrameworkScriptFile ./fructose/setup.android.sauce.js --forceExit 15 | -------------------------------------------------------------------------------- /ios/e2eTests/main.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import 11 | 12 | #import "AppDelegate.h" 13 | 14 | int main(int argc, char * argv[]) { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/app/src/components/app.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import PropTypes from "prop-types"; 3 | import { createDrawerNavigator } from "react-navigation"; 4 | import getNavigationScreens from "./getNavigationScreens"; 5 | import Navigation from "./navigation/navigation"; 6 | 7 | const App = ({ components }) => { 8 | const Root = createDrawerNavigator(getNavigationScreens(components), { 9 | contentComponent: Navigation 10 | }); 11 | 12 | return ; 13 | }; 14 | 15 | App.propTypes = { 16 | components: PropTypes.objectOf(PropTypes.func).isRequired 17 | }; 18 | 19 | export default App; 20 | -------------------------------------------------------------------------------- /packages/app/src/components/errorBoundaryComponent.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ErrorView from "./errorViewComponent"; 3 | 4 | export default class ErrorBoundary extends React.Component { 5 | constructor() { 6 | super(); 7 | this.state = { 8 | error: null 9 | }; 10 | } 11 | 12 | componentDidCatch(error) { 13 | this.setState({ 14 | error 15 | }); 16 | } 17 | 18 | render() { 19 | if (this.state.error) { 20 | return ; 21 | } 22 | 23 | return this.props.children; //eslint-disable-line 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /e2eTests/fructose/vendor.webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const webpack = require("webpack"); 3 | 4 | module.exports = { 5 | context: process.cwd(), 6 | entry: { 7 | vendor: ["prop-types", "react", "react-dom", "react-native-web"] 8 | }, 9 | 10 | output: { 11 | filename: "[name].dll.js", 12 | path: path.resolve("./dist/public"), 13 | library: "[name]" 14 | }, 15 | 16 | plugins: [ 17 | new webpack.DllPlugin({ 18 | path: path.join("./dist/public", "[name]-manifest.json"), 19 | name: "[name]", 20 | context: path.resolve(__dirname) 21 | }) 22 | ] 23 | }; 24 | -------------------------------------------------------------------------------- /e2eTests/scripts/android-tests.sh: -------------------------------------------------------------------------------- 1 | emulator @fructose_device -no-boot-anim & 2 | EMU_PID=$! 3 | adb wait-for-device 4 | adb reverse tcp:8081 tcp:8081 5 | adb reverse tcp:7811 tcp:7811 6 | adb reverse tcp:4723 tcp:4723 7 | ./node_modules/.bin/rnscl --searchDir ./e2eTests/ --pattern 'example/*.showcase.js' --outputFile e2eTests/fructose/components.js 8 | ./node_modules/.bin/react-native start --resetCache & 9 | BUNDLER_PID=$! 10 | ./node_modules/.bin/react-native run-android --no-packager 11 | LOGLEVEL=verbose node_modules/.bin/jest ./e2eTests/example/android.test.js --verbose --forceExit 12 | kill -9 $EMU_PID 13 | kill -9 $BUNDLER_PID -------------------------------------------------------------------------------- /ios/e2eTests.app/Frameworks/XCTest.framework/version.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BuildAliasOf 6 | XCTest 7 | BuildVersion 8 | 4 9 | CFBundleShortVersionString 10 | 1.0 11 | CFBundleVersion 12 | 12124 13 | ProjectName 14 | XCTest_Sim 15 | SourceVersion 16 | 12124000000000000 17 | 18 | 19 | -------------------------------------------------------------------------------- /packages/app/src/components/navigation/parentNavigationItem.test.js: -------------------------------------------------------------------------------- 1 | /* globals describe beforeEach it expect */ 2 | 3 | import React from "react"; 4 | import { configure, shallow } from "enzyme"; 5 | import Adapter from "enzyme-adapter-react-16"; 6 | import ParentNavigationItem from "./parentNavigationItem"; 7 | 8 | configure({ 9 | adapter: new Adapter() 10 | }); 11 | 12 | describe("Parent Navigation Header", () => { 13 | let app; 14 | 15 | it("Renders without back icon", () => { 16 | app = shallow( 17 | {}} /> 18 | ); 19 | expect(app).toMatchSnapshot(); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /packages/app/src/components/navigation/__snapshots__/navigation.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Navigation renders when is child menu 1`] = ` 4 | Array [ 5 | , 10 | , 13 | ] 14 | `; 15 | 16 | exports[`Navigation renders when is parent menu 1`] = ` 17 | Array [ 18 | , 23 | , 26 | ] 27 | `; 28 | -------------------------------------------------------------------------------- /ios/e2eTests.app/Frameworks/XCTest.framework/XPCServices/XCUIRecorderService.xpc/version.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BuildAliasOf 6 | XCTest 7 | BuildVersion 8 | 4 9 | CFBundleShortVersionString 10 | 1.0 11 | CFBundleVersion 12 | 1 13 | ProjectName 14 | XCTest_Sim 15 | SourceVersion 16 | 12124000000000000 17 | 18 | 19 | -------------------------------------------------------------------------------- /ios/e2eTests.app/Frameworks/XCTest.framework/XPCServices/xctestSymbolicator.xpc/version.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BuildAliasOf 6 | XCTest 7 | BuildVersion 8 | 4 9 | CFBundleShortVersionString 10 | 1.0 11 | CFBundleVersion 12 | 1 13 | ProjectName 14 | XCTest_Sim 15 | SourceVersion 16 | 12124000000000000 17 | 18 | 19 | -------------------------------------------------------------------------------- /ios/e2eTests.app/Frameworks/IDEBundleInjection.framework/version.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BuildAliasOf 6 | IDEBundleInjection 7 | BuildVersion 8 | 49 9 | CFBundleShortVersionString 10 | 5.0 11 | CFBundleVersion 12 | 12002 13 | ProjectName 14 | IDEBundleInjection_Sim 15 | SourceVersion 16 | 12002000000000000 17 | 18 | 19 | -------------------------------------------------------------------------------- /packages/app/src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import App from "./components/app"; 3 | import componentLoader from "./componentLoader"; 4 | 5 | const defaultPlatform = "native"; 6 | 7 | export default (componentsToLoad, config) => () => { 8 | // disable red + yellow pop ups and allow our own error component to render 9 | console._errorOriginal = console.error.bind(console); // eslint-disable-line 10 | console.error = () => {}; // eslint-disable-line 11 | console.disableYellowBox = true; // eslint-disable-line 12 | 13 | const platform = config.platform || defaultPlatform; 14 | const components = componentLoader(componentsToLoad, platform); 15 | 16 | return ; 17 | }; 18 | -------------------------------------------------------------------------------- /packages/app/src/components/getNavigationScreens.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ErrorBoundary from "./errorBoundaryComponent"; 3 | import FructoseComponentWrapper from "./fructoseComponentWrapper"; 4 | import LoadingScreen from "./loadingScreen"; 5 | 6 | export default componentsToLoad => { 7 | const navigationList = { 8 | Home: { 9 | screen: LoadingScreen 10 | } 11 | }; 12 | 13 | Object.keys(componentsToLoad).forEach(component => { 14 | navigationList[component] = { 15 | screen: () => ( 16 | 17 | 18 | 19 | ) 20 | }; 21 | }); 22 | 23 | return navigationList; 24 | }; 25 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:2.2.3' 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | mavenLocal() 18 | jcenter() 19 | maven { 20 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm 21 | url "$rootDir/../node_modules/react-native/android" 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /packages/app/src/components/app.test.js: -------------------------------------------------------------------------------- 1 | /* globals describe beforeEach it expect */ 2 | 3 | import React from "react"; 4 | import { View } from "react-native"; 5 | import { configure, shallow } from "enzyme"; 6 | import Adapter from "enzyme-adapter-react-16"; 7 | import App from "./app"; 8 | 9 | configure({ adapter: new Adapter() }); 10 | 11 | describe("App", () => { 12 | let app; 13 | let components; 14 | 15 | beforeEach(() => { 16 | components = { 17 | component1: () => , 18 | component2: () => , 19 | component3: () => 20 | }; 21 | }); 22 | 23 | it("Renders the root stack", () => { 24 | app = shallow(); 25 | 26 | expect(app).toMatchSnapshot(); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /e2eTests/example/android.test.js: -------------------------------------------------------------------------------- 1 | import showcases from "./component-pages.showcase"; 2 | import { setup, teardown } from "./setup.native.hooks"; 3 | 4 | describe("Android example tests", () => { 5 | let fructoseClient; 6 | 7 | beforeAll(async () => { 8 | fructoseClient = await setup(); 9 | }, 18000); 10 | 11 | it("loads all expected components ", async () => { 12 | expect.assertions(showcases.children.length); 13 | 14 | for (let i = 0; i < showcases.children.length; i++) { 15 | const result = await fructoseClient.loadComponent( 16 | `${showcases.name}:${showcases.children[i].name}` 17 | ); 18 | expect(result).toBe("component loaded"); 19 | } 20 | }); 21 | 22 | afterAll(() => { 23 | teardown(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /e2eTests/example/ios.test.js: -------------------------------------------------------------------------------- 1 | import io from "socket.io-client"; 2 | import showcases from "./component-pages.showcase"; 3 | import { setup, teardown } from "./setup.native.hooks"; 4 | 5 | describe("IOS example tests", () => { 6 | let fructoseClient; 7 | 8 | beforeAll(async () => { 9 | fructoseClient = await setup(); 10 | }, 18000); 11 | 12 | it("loads all expected components ", async () => { 13 | expect.assertions(showcases.children.length); 14 | 15 | for (let i = 0; i < showcases.children.length; i++) { 16 | const result = await fructoseClient.loadComponent( 17 | `${showcases.name}:${showcases.children[i].name}` 18 | ); 19 | expect(result).toBe("component loaded"); 20 | } 21 | }); 22 | 23 | afterAll(() => { 24 | teardown(); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /ios/e2eTests/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /packages/common/logger.js: -------------------------------------------------------------------------------- 1 | const log = require("npmlog"); 2 | 3 | log.level = process.env.LOGLEVEL || "info"; 4 | log.stream = process.stdout; 5 | log.enableColor(); 6 | log.info("logger", `Log level is ${log.level}`); 7 | 8 | module.exports = { 9 | info: (fileName, textToLog) => { 10 | log.stream = process.stdout; 11 | log.prefixStyle = { fg: "green", bg: "black" }; 12 | log.info(`[${fileName}] :`, textToLog); 13 | }, 14 | verbose: (fileName, textToLog) => { 15 | log.stream = process.stdout; 16 | log.prefixStyle = { fg: "blue" }; 17 | log.verbose(`[${fileName}] :`, textToLog); 18 | }, 19 | error: (fileName, textToError) => { 20 | log.stream = process.stdout; 21 | log.prefixStyle = { fg: "red" }; 22 | log.error(`[${fileName}] :`, textToError); 23 | } 24 | }; 25 | -------------------------------------------------------------------------------- /ios/e2eTests.app/PlugIns/e2eTestsTests.xctest.dSYM/Contents/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleIdentifier 8 | com.apple.xcode.dsym.org.reactjs.native.example.e2eTestsTests 9 | CFBundleInfoDictionaryVersion 10 | 6.0 11 | CFBundlePackageType 12 | dSYM 13 | CFBundleSignature 14 | ???? 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleVersion 18 | 1 19 | 20 | 21 | -------------------------------------------------------------------------------- /ios/e2eTestsTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /packages/test-helpers/bin/createTunnel.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const fs = require("fs"); 4 | const ngrok = require("ngrok"); 5 | const path = require("path"); 6 | const log = require("../../common/logger"); 7 | 8 | function serverUrlString(url) { 9 | const json = { 10 | "server-url": url 11 | }; 12 | return `${JSON.stringify(json)}\n`; 13 | } 14 | 15 | function writeProperties(contents) { 16 | fs.writeFile( 17 | path.join(__dirname, "./../../app/src/properties.json"), 18 | contents, 19 | err => { 20 | if (err) throw err; 21 | log.info("createTunnel", "Properties file updated"); 22 | } 23 | ); 24 | } 25 | 26 | if (process.env.LOCAL) { 27 | writeProperties(serverUrlString("http://localhost:7811")); 28 | } else { 29 | ngrok.connect(7811, (err, url) => { 30 | if (err) throw err; 31 | writeProperties(serverUrlString(url)); 32 | }); 33 | } 34 | -------------------------------------------------------------------------------- /ios/e2eTests.app/Frameworks/XCTest.framework/Headers/XCTestErrors.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2014-2015 Apple Inc. All rights reserved. 3 | // 4 | 5 | #import 6 | 7 | /*! 8 | * @const XCTestErrorDomain 9 | * Domain for errors provided by the XCTest framework. 10 | */ 11 | XCT_EXPORT NSString *const XCTestErrorDomain; 12 | 13 | /*! 14 | * @typedef XCTestErrorCode 15 | * Error codes used with errors in the XCTestErrorDomain. 16 | * 17 | * @constant XCTestErrorCodeTimeoutWhileWaiting Indicates that a call to -waitForExpectationsWithTimeout:handler: timed out. 18 | * @constant XCTestErrorCodeFailureWhileWaiting Indicates that a failure assertion was raised while waiting in -waitForExpectationsWithTimeout:handler:. 19 | */ 20 | typedef NS_ENUM(NSInteger, XCTestErrorCode) { 21 | XCTestErrorCodeTimeoutWhileWaiting, 22 | XCTestErrorCodeFailureWhileWaiting, 23 | }; 24 | 25 | -------------------------------------------------------------------------------- /packages/app/src/components/navigation/navigationHeader.test.js: -------------------------------------------------------------------------------- 1 | /* globals describe beforeEach it expect */ 2 | 3 | import React from "react"; 4 | import { configure, shallow } from "enzyme"; 5 | import Adapter from "enzyme-adapter-react-16"; 6 | import NavigationHeader from "./navigationHeader"; 7 | 8 | configure({ 9 | adapter: new Adapter() 10 | }); 11 | 12 | describe("Navigation Header", () => { 13 | let app; 14 | 15 | it("Renders without back icon", () => { 16 | app = shallow( 17 | {}} 19 | isParentMenu={() => true} 20 | /> 21 | ); 22 | expect(app).toMatchSnapshot(); 23 | }); 24 | 25 | it("Renders with back icon", () => { 26 | app = shallow( 27 | {}} 29 | isParentMenu={() => false} 30 | /> 31 | ); 32 | expect(app).toMatchSnapshot(); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /e2eTests/example/web.test.js: -------------------------------------------------------------------------------- 1 | import io from "socket.io-client"; 2 | import showcases from "./component-pages.showcase"; 3 | import fructose from "./../../setup"; 4 | 5 | describe("Web example tests", () => { 6 | let fructoseClient; 7 | let chrome; 8 | 9 | beforeAll(async () => { 10 | jasmine.DEFAULT_TIMEOUT_INTERVAL = 25000; 11 | 12 | const { client, chromeless } = await fructose.hooks.web.setup(3000, 60000); 13 | fructoseClient = client; 14 | 15 | //for examples benefit 16 | chrome = chromeless; 17 | }, 60000); 18 | 19 | it("loads all expected components ", async () => { 20 | expect.assertions(showcases.children.length); 21 | 22 | for (let i = 0; i < showcases.children.length; i++) { 23 | const result = await fructoseClient.loadComponent( 24 | `${showcases.name}:${showcases.children[i].name}` 25 | ); 26 | 27 | expect(result).toBe("component loaded"); 28 | } 29 | }); 30 | 31 | afterAll(async () => { 32 | await fructose.hooks.web.cleanup(); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /packages/app/src/components/errorViewComponent.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { View, Text, StyleSheet, StatusBar } from "react-native"; 3 | import PropTypes from "prop-types"; 4 | 5 | const styles = StyleSheet.create({ 6 | errorContainer: { 7 | backgroundColor: "#B20000", 8 | height: "100%" 9 | }, 10 | errorHeader: { 11 | fontWeight: "bold", 12 | fontSize: 24, 13 | color: "white", 14 | textAlign: "center" 15 | }, 16 | stackTrace: { 17 | color: "white", 18 | fontSize: 16 19 | } 20 | }); 21 | 22 | const ErrorState = props => ( 23 | 24 | 28 | ); 29 | 30 | ErrorState.propTypes = { 31 | error: PropTypes.shape({ 32 | message: PropTypes.string, 33 | stack: PropTypes.string 34 | }) 35 | }; 36 | 37 | ErrorState.defaultProps = { 38 | error: {} 39 | }; 40 | 41 | export default ErrorState; 42 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | 20 | android.useDeprecatedNdk=true 21 | STORE_FILE=fructose.keystore 22 | RELEASE_KEY_ALIAS=fructose 23 | STORE_PASSWORD=fructose 24 | RELEASE_KEY_PASSWORD=fructose 25 | -------------------------------------------------------------------------------- /packages/app/src/components/fructoseComponentWrapper.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import PropTypes from "prop-types"; 3 | import { StyleSheet, View, StatusBar, Text } from "react-native"; 4 | 5 | const styles = StyleSheet.create({ 6 | container: { 7 | backgroundColor: "white", 8 | height: "100%", 9 | width: "100%" 10 | } 11 | }); 12 | 13 | const knobs = { 14 | select: () => {}, 15 | color: () => {}, 16 | selectV2: () => {}, 17 | text: () => {}, 18 | number: () => {}, 19 | boolean: () => {}, 20 | array: () => {}, 21 | radio: () => {}, 22 | date: () => {}, 23 | button: () => {}, 24 | e2eTestDontDelete: () => YAY I RENDERED 25 | }; 26 | 27 | const actions = { 28 | action: () => {}, 29 | decorateAction: () => () => {} 30 | }; 31 | 32 | const FructoseComponentWrapper = ({ component }) => ( 33 | 34 | 37 | ); 38 | 39 | FructoseComponentWrapper.propTypes = { 40 | component: PropTypes.func.isRequired 41 | }; 42 | 43 | export default FructoseComponentWrapper; 44 | -------------------------------------------------------------------------------- /packages/app/src/components/loadingScreen.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { StyleSheet, Text, View } from "react-native"; 3 | import { version } from "../../../../package.json"; 4 | 5 | const styles = StyleSheet.create({ 6 | header: { 7 | color: "white", 8 | fontSize: 40, 9 | textAlign: "center" 10 | }, 11 | version: { 12 | padding: 10, 13 | color: "white", 14 | fontSize: 20, 15 | textAlign: "left" 16 | }, 17 | text: { 18 | paddingTop: 10, 19 | color: "white", 20 | fontSize: 16, 21 | textAlign: "center" 22 | }, 23 | view: { 24 | backgroundColor: "lightpink", 25 | height: "100%", 26 | width: "100%", 27 | flex: 1, 28 | flexDirection: "column", 29 | justifyContent: "space-between" 30 | } 31 | }); 32 | 33 | const LoadingScreen = () => ( 34 | 35 | 36 | Brought to you by {"\n"} The Times Tooling Team 37 | 38 | 🛠 FRUCTOSE 🛠 39 | Version: {version} 40 | 41 | ); 42 | 43 | export default LoadingScreen; 44 | -------------------------------------------------------------------------------- /packages/app/src/components/errorBoundaryComponent.test.js: -------------------------------------------------------------------------------- 1 | /* globals it expect */ 2 | 3 | import React from "react"; 4 | import { Text } from "react-native"; 5 | import { EventEmitter } from "events"; 6 | import renderer from "react-test-renderer"; 7 | 8 | import ErrorBoundary from "./errorBoundaryComponent"; 9 | 10 | const ThrowAnError = () => {lol}; // eslint-disable-line 11 | 12 | describe("Error Boundary", () => { 13 | it("It renders the error View when error is triggered", () => { 14 | const wrapper = renderer 15 | .create( 16 | 17 | 18 | 19 | ) 20 | .toJSON(); 21 | 22 | expect(wrapper).toMatchSnapshot(); 23 | }); 24 | 25 | it("it render a component when there is no error", () => { 26 | const wrapper = renderer 27 | .create( 28 | 29 | Hey I rendered 30 | 31 | ) 32 | .toJSON(); 33 | 34 | expect(wrapper).toMatchSnapshot(); 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/e2etests/MainApplication.java: -------------------------------------------------------------------------------- 1 | package com.e2etests; 2 | 3 | import android.app.Application; 4 | 5 | import com.facebook.react.ReactApplication; 6 | import com.facebook.react.ReactNativeHost; 7 | import com.facebook.react.ReactPackage; 8 | import com.facebook.react.shell.MainReactPackage; 9 | import com.facebook.soloader.SoLoader; 10 | 11 | import java.util.Arrays; 12 | import java.util.List; 13 | 14 | public class MainApplication extends Application implements ReactApplication { 15 | 16 | private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) { 17 | @Override 18 | public boolean getUseDeveloperSupport() { 19 | return BuildConfig.DEBUG; 20 | } 21 | 22 | @Override 23 | protected List getPackages() { 24 | return Arrays.asList( 25 | new MainReactPackage() 26 | ); 27 | } 28 | }; 29 | 30 | @Override 31 | public ReactNativeHost getReactNativeHost() { 32 | return mReactNativeHost; 33 | } 34 | 35 | @Override 36 | public void onCreate() { 37 | super.onCreate(); 38 | SoLoader.init(this, /* native exopackage */ false); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /packages/test-helpers/src/didWebStart.js: -------------------------------------------------------------------------------- 1 | import request from "request"; 2 | import EventEmitter from "events"; 3 | 4 | const isWebStarted = port => 5 | new Promise(resolve => { 6 | request( 7 | { 8 | uri: `http://localhost:${port}`, 9 | timeout: 1000 10 | }, 11 | error => { 12 | if (error) { 13 | resolve(false); 14 | } else { 15 | resolve(true); 16 | } 17 | } 18 | ); 19 | }); 20 | 21 | export default (port, timeout) => 22 | new Promise(resolve => { 23 | const intervalLength = 1100; 24 | let intervals = timeout / intervalLength; 25 | const event = new EventEmitter(); 26 | event.on("taken", taken => { 27 | resolve(taken); 28 | }); 29 | let taken; 30 | const interval = setInterval(async () => { 31 | intervals -= 1; 32 | taken = await isWebStarted(port, timeout); 33 | if (taken) { 34 | event.emit("taken", true); 35 | clearInterval(interval); 36 | } 37 | if (!taken && intervals === 0) { 38 | event.emit("taken", false); 39 | clearInterval(interval); 40 | } 41 | }, intervalLength); 42 | }); 43 | -------------------------------------------------------------------------------- /packages/app/src/components/__snapshots__/errorBoundaryComponent.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Error Boundary It renders the error View when error is triggered 1`] = ` 4 | 12 | 25 | Exception Found 26 | 27 | 38 | lol is not defined 39 | 40 | 41 | `; 42 | 43 | exports[`Error Boundary it render a component when there is no error 1`] = ` 44 | 49 | Hey I rendered 50 | 51 | `; 52 | -------------------------------------------------------------------------------- /packages/app/src/components/navigation/parentNavigationItem.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { TouchableOpacity, View, Text, StyleSheet, Image } from "react-native"; 3 | import PropTypes from "prop-types"; 4 | import forwardIcon from "./forward-icon.png"; 5 | 6 | const styles = StyleSheet.create({ 7 | menuHeaderText: { 8 | color: "gray", 9 | fontSize: 14, 10 | fontWeight: "bold" 11 | }, 12 | button: { 13 | paddingTop: 21, 14 | paddingBottom: 16, 15 | paddingLeft: 15, 16 | paddingRight: 10 17 | }, 18 | image: { 19 | width: 20, 20 | height: 20 21 | } 22 | }); 23 | 24 | const ParentNavigationItem = ({ label, onPress }) => ( 25 | 26 | 32 | {label} 33 | 34 | 35 | 36 | ); 37 | 38 | ParentNavigationItem.propTypes = { 39 | label: PropTypes.string.isRequired, 40 | onPress: PropTypes.func.isRequired 41 | }; 42 | 43 | export default ParentNavigationItem; 44 | -------------------------------------------------------------------------------- /packages/app/src/componentLoader.js: -------------------------------------------------------------------------------- 1 | const isValidShowcase = parent => { 2 | if (!parent) return false; 3 | if (!parent.default) return false; 4 | if (!parent.default.children) return false; 5 | return true; 6 | }; 7 | 8 | const filterShowcases = (showcases, platform) => 9 | showcases.children 10 | .filter(showcase => showcase.type === "story") 11 | .filter(showcase => !showcase.hasExternalDeps) 12 | .filter(showcase => { 13 | if (showcase.platform) { 14 | return showcase.platform.includes(platform); 15 | } 16 | return showcase; 17 | }); 18 | 19 | export default (loadComponents, platform) => { 20 | const componentsStore = {}; 21 | const components = loadComponents(); 22 | 23 | if (components) { 24 | components.forEach(parent => { 25 | if (isValidShowcase(parent)) { 26 | const showcases = parent.default; 27 | const filteredShowcases = filterShowcases(showcases, platform); 28 | 29 | filteredShowcases.forEach(showcase => { 30 | const showCaseName = `${showcases.name}:${ 31 | showcase.name 32 | }`.toLowerCase(); 33 | componentsStore[showCaseName] = showcase.component; 34 | }); 35 | } 36 | }); 37 | } 38 | return componentsStore; 39 | }; 40 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 12 | 13 | 19 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /packages/app/src/components/navigation/__snapshots__/parentNavigationItem.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Parent Navigation Header Renders without back icon 1`] = ` 4 | 16 | 24 | 36 | 37 | label to render 38 | 39 | 52 | 53 | 54 | `; 55 | -------------------------------------------------------------------------------- /ios/e2eTests.app/Frameworks/XCTest.framework/Headers/XCUISiriService.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2017 Apple Inc. All rights reserved. 3 | // 4 | 5 | #import 6 | 7 | NS_ASSUME_NONNULL_BEGIN 8 | 9 | #if XCT_UI_TESTING_AVAILABLE && TARGET_OS_IOS 10 | 11 | /*! 12 | * @class XCUISiriService 13 | * Represents a device's Siri interface and allows issuing textual queries 14 | * and producing element queries for UI shown by Siri. 15 | */ 16 | NS_CLASS_AVAILABLE_IOS(10_3) 17 | @interface XCUISiriService : NSObject 18 | 19 | + (instancetype)new NS_UNAVAILABLE; 20 | - (instancetype)init NS_UNAVAILABLE; 21 | 22 | /*! 23 | * Provides debugging information about the element representing the root of the Siri UI. 24 | * @seealso XCUIElement 25 | */ 26 | @property (readonly, copy) NSString *debugDescription; 27 | 28 | /*! 29 | * Presents the Siri UI, if it is not currently active, and accepts a string 30 | * which is then processed as if it were recognized speech. 31 | * 32 | * @param text The string to pass to Siri for processing. 33 | */ 34 | - (void)activateWithVoiceRecognitionText:(NSString *)text NS_SWIFT_NAME(activate(voiceRecognitionText:)); 35 | 36 | @end 37 | 38 | @interface XCUISiriService (XCUIElementTypeQueryProvider) 39 | @end 40 | 41 | #endif 42 | 43 | NS_ASSUME_NONNULL_END 44 | -------------------------------------------------------------------------------- /packages/client/client.js: -------------------------------------------------------------------------------- 1 | const log = require("../common/logger"); 2 | 3 | class FructoseClient { 4 | constructor(socketClient) { 5 | this.socket = socketClient; 6 | } 7 | 8 | waitForApp() { 9 | return new Promise(resolve => { 10 | log.verbose("fructose Client", "waiting for app to boot"); 11 | this.socket.on("fructose-app-ready", () => { 12 | log.info("fructose Client", "fructose app Loaded 💯"); 13 | resolve(); 14 | }); 15 | }); 16 | } 17 | 18 | getLoadedComponents() { 19 | return new Promise(resolve => { 20 | this.socket.on("send-loaded-app-components", componentList => { 21 | resolve(componentList); 22 | }); 23 | log.verbose("fructose Client", "getting loaded app components"); 24 | this.socket.emit("get-loaded-app-components"); 25 | }); 26 | } 27 | 28 | loadComponent(component) { 29 | return new Promise(resolve => { 30 | this.socket.on("component-loaded-in-app", () => { 31 | log.info("fructose client", `component loaded: ${component}`); 32 | this.socket.removeListener("component-loaded-in-app"); 33 | resolve("component loaded"); 34 | }); 35 | 36 | log.info("fructose client", `loading component: ${component}`); 37 | this.socket.emit("load-component-in-app", component); 38 | }); 39 | } 40 | 41 | disconnect() { 42 | this.socket.disconnect(); 43 | log.info("fructose client", "client terminated"); 44 | } 45 | } 46 | 47 | module.exports = FructoseClient; 48 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Xcode 6 | # 7 | build/ 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | *.xccheckout 18 | *.moved-aside 19 | DerivedData 20 | *.hmap 21 | *.ipa 22 | *.xcuserstate 23 | project.xcworkspace 24 | 25 | # Android/IntelliJ 26 | # 27 | build/ 28 | .idea 29 | .gradle 30 | local.properties 31 | *.iml 32 | 33 | # vscode 34 | € 35 | .vscode 36 | 37 | # node.js 38 | # 39 | node_modules/ 40 | npm-debug.log 41 | yarn-error.log 42 | 43 | # BUCK 44 | buck-out/ 45 | \.buckd/ 46 | 47 | # fastlane 48 | # 49 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 50 | # screenshots whenever they are needed. 51 | # For more information about the recommended setup visit: 52 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 53 | 54 | fastlane/report.xml 55 | fastlane/Preview.html 56 | fastlane/screenshots 57 | 58 | #coverage 59 | **/coverage 60 | .nyc_output/** 61 | sandbox 62 | 63 | # babeled stuff 64 | packages/test-helpers/lib/** 65 | 66 | # ejs template 67 | packages/web/templates/** 68 | 69 | **/.fructose/components.js 70 | **/.fructose/components.test.js 71 | **/fructose/components.js 72 | **/fructose/components.test.js 73 | 74 | !dist 75 | !dist/public 76 | dist/public/** 77 | !dist/public/react-logo.png 78 | packages/web/dist/* 79 | 80 | **/__snapshots__/*/tmp 81 | **/vendor-dev 82 | **/vendor 83 | -------------------------------------------------------------------------------- /ios/e2eTests/AppDelegate.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import "AppDelegate.h" 11 | 12 | #import 13 | #import 14 | 15 | @implementation AppDelegate 16 | 17 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 18 | { 19 | NSURL *jsCodeLocation; 20 | 21 | jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil]; 22 | 23 | RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation 24 | moduleName:@"e2eTests" 25 | initialProperties:nil 26 | launchOptions:launchOptions]; 27 | rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1]; 28 | 29 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 30 | UIViewController *rootViewController = [UIViewController new]; 31 | rootViewController.view = rootView; 32 | self.window.rootViewController = rootViewController; 33 | [self.window makeKeyAndVisible]; 34 | return YES; 35 | } 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /e2eTests/fructose/setup.android.sauce.js: -------------------------------------------------------------------------------- 1 | /* globals beforeAll afterAll jasmine */ 2 | import fructose from "@times-components/fructose/setup"; 3 | import wd from "wd"; 4 | 5 | const SAUCE_USERNAME = process.env.SAUCE_USERNAME; 6 | const SAUCE_KEY = process.env.SAUCE_KEY; 7 | 8 | if (!SAUCE_KEY || !SAUCE_USERNAME) { 9 | throw new Error( 10 | ` 11 | Sauce username or key is undefined. 12 | Please set the Environment Variables SAUCE_KEY and SAUCE_USERNAME 13 | ` 14 | ); 15 | } 16 | 17 | global.asserter = wd.asserters; 18 | const driver = wd.promiseChainRemote( 19 | `https://${SAUCE_USERNAME}:${SAUCE_KEY}@ondemand.saucelabs.com:443/wd/hub` 20 | ); 21 | 22 | beforeAll(async () => { 23 | await fructose.hooks.mobile.setup(); 24 | 25 | const options = { 26 | desiredCapabilities: { 27 | appiumVersion: "1.6.5", 28 | platformName: "Android", 29 | browserName: "", 30 | deviceName: "Android GoogleAPI Emulator", 31 | platformVersion: "7.1", 32 | app: "sauce-storage:fructose-e2e.apk", 33 | autoGrantPermissions: true 34 | }, 35 | host: "localhost", 36 | port: 4723 37 | }; 38 | 39 | global.driver = driver; 40 | await driver.init(options.desiredCapabilities).setImplicitWaitTimeout(300000); 41 | 42 | await global.driver.waitForElementsByXPath( 43 | '//*[@text="Fructose"]', 44 | global.asserter.isDisplayed, 45 | 1800000 46 | ); 47 | 48 | jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000000; 49 | }, 1800000); 50 | 51 | afterAll(async () => { 52 | await fructose.hooks.mobile.cleanup(); 53 | }); 54 | -------------------------------------------------------------------------------- /packages/app/src/components/navigation/navigationHeader.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { View, Text, Image, StyleSheet, TouchableOpacity } from "react-native"; 3 | import PropTypes from "prop-types"; 4 | import backIcon from "./back-icon.png"; 5 | 6 | const styles = StyleSheet.create({ 7 | menuHeaderText: { 8 | color: "gray", 9 | textAlign: "center", 10 | fontSize: 20 11 | }, 12 | menuHeader: { 13 | flexDirection: "row", 14 | backgroundColor: "skyblue", 15 | paddingVertical: 28, 16 | paddingLeft: 17, 17 | alignItems: "center" 18 | }, 19 | menuSeparator: { 20 | backgroundColor: "gray", 21 | height: StyleSheet.hairlineWidth, 22 | width: "100%" 23 | }, 24 | image: { 25 | width: 40, 26 | height: 40 27 | } 28 | }); 29 | 30 | const MenuSeparator = () => ; 31 | 32 | const renderImage = isParentMenu => 33 | isParentMenu ? ( 34 | 35 | ) : ( 36 | 37 | ); 38 | 39 | const NavigationHeader = ({ navigateToCallback, isParentMenu }) => ( 40 | navigateToCallback()}> 41 | 42 | {renderImage(isParentMenu())} 43 | Component List 44 | 45 | 46 | 47 | ); 48 | 49 | NavigationHeader.propTypes = { 50 | navigateToCallback: PropTypes.func.isRequired, 51 | isParentMenu: PropTypes.func.isRequired 52 | }; 53 | 54 | export default NavigationHeader; 55 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2017, News UK & Ireland Ltd 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /ios/e2eTests.app/Frameworks/XCTest.framework/Headers/XCTNSPredicateExpectation.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016 Apple Inc. All rights reserved. 3 | // 4 | 5 | #import 6 | #import 7 | #import 8 | 9 | NS_ASSUME_NONNULL_BEGIN 10 | 11 | /*! 12 | * @class XCTNSPredicateExpectation 13 | * Expectation subclass for waiting on a condition defined by an NSPredicate and an object. 14 | */ 15 | @interface XCTNSPredicateExpectation : XCTestExpectation { 16 | #ifndef __OBJC2__ 17 | @private 18 | id _internal; 19 | #endif 20 | } 21 | 22 | - (instancetype)init NS_UNAVAILABLE; 23 | - (instancetype)initWithDescription:(NSString *)expectationDescription NS_UNAVAILABLE; 24 | 25 | /*! 26 | * @method -initWithPredicate:object: 27 | * Initializes an expectation that waits for a predicate to evaluate as true with the provided object. 28 | */ 29 | - (instancetype)initWithPredicate:(NSPredicate *)predicate object:(nullable id)object NS_DESIGNATED_INITIALIZER; 30 | 31 | /*! 32 | * @property predicate 33 | * Returns the predicate used by the expectation. 34 | */ 35 | @property (readonly, copy) NSPredicate *predicate; 36 | 37 | /*! 38 | * @property object 39 | * Returns the object against which the predicate is evaluated. 40 | */ 41 | @property (nullable, readonly, strong) id object; 42 | 43 | /*! 44 | * @property handler 45 | * Allows the caller to install a special handler to do custom evaluation of predicate and its object. 46 | */ 47 | @property (nullable, copy) XCPredicateExpectationHandler handler; 48 | 49 | @end 50 | 51 | NS_ASSUME_NONNULL_END 52 | -------------------------------------------------------------------------------- /packages/web/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const HtmlWebpackPlugin = require("html-webpack-plugin"); 3 | const webpack = require("webpack"); 4 | 5 | const alias = { 6 | "react-native": "react-native-web" 7 | }; 8 | const extensions = [".web.js", ".js", ".jsx", ".mjs"]; 9 | const mode = "production"; 10 | 11 | const babelConfig = [ 12 | { 13 | test: /\.js$/, 14 | use: { 15 | loader: "babel-loader", 16 | options: { 17 | cacheDirectory: true, 18 | presets: ["react-native"], 19 | plugins: ["transform-regenerator", "react-native-web"] 20 | } 21 | } 22 | }, 23 | { 24 | test: /\.ttf$/, 25 | loader: "url-loader", 26 | include: path.resolve( 27 | __dirname, 28 | "../node_modules/react-native-vector-icons" 29 | ) 30 | }, 31 | { 32 | include: /node_modules/, 33 | test: /\.mjs$/, 34 | type: "javascript/auto" 35 | }, 36 | { 37 | test: /\.(gif|jpe?g|png|svg)$/, 38 | loader: "url-loader", 39 | query: { 40 | name: "images/[name]-[hash:16].[ext]" 41 | } 42 | } 43 | ]; 44 | 45 | module.exports = { 46 | mode, 47 | entry: ["babel-polyfill"], 48 | module: { 49 | rules: babelConfig 50 | }, 51 | plugins: [ 52 | new HtmlWebpackPlugin({ 53 | filename: "index.html", 54 | template: path.join(__dirname, "./index.ejs") 55 | }), 56 | new webpack.DefinePlugin({ 57 | __DEV__: JSON.stringify(JSON.parse(process.env.BUILD_DEV || "true")) 58 | }) 59 | ], 60 | output: { 61 | filename: "test.bundle.js", 62 | path: path.resolve(__dirname, "./dist") 63 | }, 64 | resolve: { 65 | alias, 66 | extensions 67 | } 68 | }; 69 | -------------------------------------------------------------------------------- /ios/e2eTests.app/Frameworks/XCTest.framework/Headers/XCUIRemote.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2014-2015 Apple Inc. All rights reserved. 3 | // 4 | 5 | #import 6 | #import 7 | 8 | NS_ASSUME_NONNULL_BEGIN 9 | 10 | #if XCT_UI_TESTING_AVAILABLE 11 | 12 | /*! 13 | * @enum XCUIRemoteButton 14 | * 15 | * A button on a physical remote control. 16 | */ 17 | typedef NS_ENUM(NSUInteger, XCUIRemoteButton) { 18 | XCUIRemoteButtonUp = 0, 19 | XCUIRemoteButtonDown = 1, 20 | XCUIRemoteButtonLeft = 2, 21 | XCUIRemoteButtonRight = 3, 22 | 23 | XCUIRemoteButtonSelect = 4, 24 | XCUIRemoteButtonMenu = 5, 25 | XCUIRemoteButtonPlayPause = 6, 26 | }; 27 | 28 | #if TARGET_OS_TV 29 | 30 | /*! 31 | * @class XCUIRemote 32 | * 33 | * Simulates interaction with a physical remote control. 34 | */ 35 | NS_CLASS_AVAILABLE_IOS(9_0) 36 | @interface XCUIRemote : NSObject 37 | 38 | /*! 39 | * The simulated physical remote control. 40 | */ 41 | + (instancetype)sharedRemote; 42 | 43 | /*! 44 | * Sends a momentary press of a button on a physical remote control. 45 | * 46 | * @param remoteButton 47 | * The button on the physical remote control for which to synthesize a press. 48 | */ 49 | - (void)pressButton:(XCUIRemoteButton)remoteButton; 50 | 51 | /*! 52 | * Sends a press and hold of a button on a physical remote control, holding for the specified duration. 53 | * 54 | * @param remoteButton 55 | * The button on the physical remote control for which to synthesize a press. 56 | * 57 | * @param duration 58 | * Duration in seconds. 59 | */ 60 | - (void)pressButton:(XCUIRemoteButton)remoteButton forDuration:(NSTimeInterval)duration; 61 | 62 | @end 63 | 64 | #endif 65 | 66 | #endif 67 | 68 | NS_ASSUME_NONNULL_END 69 | -------------------------------------------------------------------------------- /android/app/BUCK: -------------------------------------------------------------------------------- 1 | # To learn about Buck see [Docs](https://buckbuild.com/). 2 | # To run your application with Buck: 3 | # - install Buck 4 | # - `npm start` - to start the packager 5 | # - `cd android` 6 | # - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"` 7 | # - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck 8 | # - `buck install -r android/app` - compile, install and run application 9 | # 10 | 11 | lib_deps = [] 12 | 13 | for jarfile in glob(['libs/*.jar']): 14 | name = 'jars__' + jarfile[jarfile.rindex('/') + 1: jarfile.rindex('.jar')] 15 | lib_deps.append(':' + name) 16 | prebuilt_jar( 17 | name = name, 18 | binary_jar = jarfile, 19 | ) 20 | 21 | for aarfile in glob(['libs/*.aar']): 22 | name = 'aars__' + aarfile[aarfile.rindex('/') + 1: aarfile.rindex('.aar')] 23 | lib_deps.append(':' + name) 24 | android_prebuilt_aar( 25 | name = name, 26 | aar = aarfile, 27 | ) 28 | 29 | android_library( 30 | name = "all-libs", 31 | exported_deps = lib_deps, 32 | ) 33 | 34 | android_library( 35 | name = "app-code", 36 | srcs = glob([ 37 | "src/main/java/**/*.java", 38 | ]), 39 | deps = [ 40 | ":all-libs", 41 | ":build_config", 42 | ":res", 43 | ], 44 | ) 45 | 46 | android_build_config( 47 | name = "build_config", 48 | package = "com.e2etests", 49 | ) 50 | 51 | android_resource( 52 | name = "res", 53 | package = "com.e2etests", 54 | res = "src/main/res", 55 | ) 56 | 57 | android_binary( 58 | name = "app", 59 | keystore = "//android/keystores:debug", 60 | manifest = "src/main/AndroidManifest.xml", 61 | package_type = "debug", 62 | deps = [ 63 | ":app-code", 64 | ], 65 | ) 66 | -------------------------------------------------------------------------------- /ios/e2eTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | e2eTests 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | LSRequiresIPhoneOS 26 | 27 | UILaunchStoryboardName 28 | LaunchScreen 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UIViewControllerBasedStatusBarAppearance 40 | 41 | NSLocationWhenInUseUsageDescription 42 | 43 | NSAppTransportSecurity 44 | 45 | 46 | NSExceptionDomains 47 | 48 | localhost 49 | 50 | NSExceptionAllowsInsecureHTTPLoads 51 | 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /packages/test-helpers/src/setup.js: -------------------------------------------------------------------------------- 1 | import "babel-polyfill"; 2 | import { Chromeless } from "chromeless"; 3 | import { FructoseServer } from "../../server"; 4 | import log from "../../common/logger"; 5 | import checkIfWebStarted from "./didWebStart"; 6 | import fructoseClient from "../../client"; 7 | 8 | const fructosePort = 7811; 9 | let server; 10 | let client; 11 | let chromeless; 12 | 13 | const mobileHooks = () => { 14 | const setup = async () => { 15 | server = new FructoseServer(fructosePort); 16 | 17 | await server 18 | .start() 19 | .then(() => 20 | log.verbose( 21 | "setup", 22 | `fructose server started on port : ${fructosePort}` 23 | ) 24 | ); 25 | 26 | client = fructoseClient(fructosePort); 27 | await client.waitForApp(); 28 | return client; 29 | }; 30 | 31 | const cleanup = () => { 32 | client.disconnect(); 33 | server.close(); 34 | }; 35 | 36 | return { setup, cleanup }; 37 | }; 38 | 39 | const webHooks = () => { 40 | const setup = async (port, timeout) => { 41 | const appStarted = await checkIfWebStarted(port, timeout); 42 | if (!appStarted) { 43 | throw new Error( 44 | "App did not start. Run 'fructose-web --build-dir path/to/dir' first" 45 | ); 46 | } 47 | server = new FructoseServer(fructosePort); 48 | 49 | await server.start(); 50 | 51 | client = fructoseClient(fructosePort); 52 | 53 | chromeless = new Chromeless() 54 | .goto("http://localhost:3000") 55 | .exists("[data-testid='fructose']"); 56 | 57 | await client.waitForApp(); 58 | return { client, chromeless }; 59 | }; 60 | 61 | const cleanup = async () => { 62 | await chromeless.end(); 63 | client.disconnect(); 64 | server.close(); 65 | }; 66 | 67 | return { setup, cleanup }; 68 | }; 69 | export default { 70 | web: webHooks(), 71 | mobile: mobileHooks() 72 | }; 73 | -------------------------------------------------------------------------------- /packages/test-helpers/src/bin/github-comment-manager.js: -------------------------------------------------------------------------------- 1 | import { read, remove, create } from "github-comment-manager"; 2 | 3 | require("babel-polyfill"); 4 | 5 | const commentHeader = 6 | "If you use Expo, view our components by scanning this qr code:
"; 7 | 8 | const filterExpoComments = comments => 9 | JSON.parse(comments) 10 | .filter(({ body }) => body.includes(commentHeader)) 11 | .map(({ id }) => id); 12 | 13 | const getExpoComments = (account, token, pullRequest, repository) => 14 | read 15 | .comments({ 16 | account, 17 | token, 18 | pullRequest, 19 | repository 20 | }) 21 | .then(comments => filterExpoComments(comments)); 22 | 23 | const deleteComment = (commentId, account, token, repository) => 24 | remove.comment({ 25 | account, 26 | token, 27 | repository, 28 | commentId 29 | }); 30 | 31 | const deleteCommentsFromList = (comments, account, token, repository) => 32 | Promise.all( 33 | comments.map(commentId => 34 | deleteComment(commentId, account, token, repository) 35 | ) 36 | ).then(() => comments.length); 37 | 38 | const createNewExpoComment = ( 39 | account, 40 | token, 41 | documentPath, 42 | pullRequest, 43 | repository 44 | ) => 45 | create.comment({ 46 | account, 47 | token, 48 | repository, 49 | comment: `${commentHeader}

This has been made possible through [Fructose](https://github.com/newsuk/fructose) `, 50 | pullRequest 51 | }); 52 | 53 | const deleteAllExpoComments = async ( 54 | account, 55 | token, 56 | pullRequest, 57 | repository 58 | ) => { 59 | const comments = await getExpoComments( 60 | account, 61 | token, 62 | pullRequest, 63 | repository 64 | ); 65 | return deleteCommentsFromList(comments, account, token, repository); 66 | }; 67 | 68 | export default { 69 | deleteAllExpoComments, 70 | createNewExpoComment 71 | }; 72 | -------------------------------------------------------------------------------- /packages/test-helpers/src/bin/run.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import program from "commander"; 4 | import githubCommentManager from "./github-comment-manager"; 5 | import log from "../../../common/logger"; 6 | 7 | program 8 | .command("publish-QR-code") 9 | .alias("pqr") 10 | .option("-p, --path [path]", "the path to your qr code image") 11 | .option( 12 | "-a, --accountName [accountName]", 13 | "github account name, used to publish to the pull request as a comment" 14 | ) 15 | .option( 16 | "-k --key [key]", 17 | "github account key, used to publish to the pull request as a comment" 18 | ) 19 | .option( 20 | "-i --issueNumber [issueNumber]", 21 | "github issue number for the pull request you wish to post to" 22 | ) 23 | .option( 24 | "-r --repository [repository]", 25 | "gitbug organisation and repo e.g. newsuk/times-components" 26 | ) 27 | .action(async options => { 28 | const { path, accountName, key, issueNumber, repository } = options; 29 | 30 | if (!path) 31 | log.error("publish-QR-code", "no path for generated qrcode, use -p"); 32 | if (!accountName) 33 | log.error("publish-QR-code", "no github account name, use -a"); 34 | if (!key) log.error("publish-QR-code", "no github account key, use -k"); 35 | if (!issueNumber) 36 | log.error("publish-QR-code", "no github issue number, use -i"); 37 | if (!repository) 38 | log.error( 39 | "publish-QR-code", 40 | "no git organisation and repository specified" 41 | ); 42 | if (!path || !accountName || !key || !issueNumber || !repository) 43 | process.exit(1); 44 | await githubCommentManager.deleteAllExpoComments( 45 | accountName, 46 | key, 47 | issueNumber, 48 | repository 49 | ); 50 | await githubCommentManager.createNewExpoComment( 51 | accountName, 52 | key, 53 | path, 54 | issueNumber, 55 | repository 56 | ); 57 | }); 58 | program.parse(process.argv); 59 | -------------------------------------------------------------------------------- /ios/e2eTests.app/Frameworks/XCTest.framework/Headers/XCUIDevice.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2014-2015 Apple Inc. All rights reserved. 3 | // 4 | 5 | #import 6 | #import 7 | 8 | #if XCT_UI_TESTING_AVAILABLE 9 | 10 | #if TARGET_OS_IPHONE 11 | 12 | #import 13 | 14 | NS_ASSUME_NONNULL_BEGIN 15 | 16 | /*! 17 | * @enum XCUIDeviceButton 18 | * 19 | * Represents a physical button on a device. 20 | * 21 | * @note Some buttons are not available in the Simulator, and should not be used in your tests. 22 | * You can use a block like this: 23 | * 24 | * #if !TARGET_OS_SIMULATOR 25 | * // test code that depends on buttons not available in the Simulator 26 | * #endif 27 | * 28 | * in your test code to ensure it does not call unavailable APIs. 29 | */ 30 | typedef NS_ENUM(NSInteger, XCUIDeviceButton) { 31 | XCUIDeviceButtonHome = 1, 32 | XCUIDeviceButtonVolumeUp XCTEST_SIMULATOR_UNAVAILABLE("This API is not available in the Simulator, see the XCUIDeviceButton documentation for details.") = 2, 33 | XCUIDeviceButtonVolumeDown XCTEST_SIMULATOR_UNAVAILABLE("This API is not available in the Simulator, see the XCUIDeviceButton documentation for details.") = 3 34 | }; 35 | 36 | /*! Represents a device, providing an interface for simulating events involving physical buttons and device state. */ 37 | NS_CLASS_AVAILABLE(NA, 9_0) 38 | @interface XCUIDevice : NSObject 39 | 40 | /*! The current device. */ 41 | + (XCUIDevice *)sharedDevice; 42 | 43 | #if TARGET_OS_IOS 44 | /*! The orientation of the device. */ 45 | @property (nonatomic) UIDeviceOrientation orientation; 46 | 47 | /*! 48 | * Provides access to an object representing the Siri interface on the device. 49 | */ 50 | @property (readonly) XCUISiriService *siriService NS_AVAILABLE_IOS(10_3); 51 | #endif 52 | 53 | /*! Simulates the user pressing a physical button. */ 54 | - (void)pressButton:(XCUIDeviceButton)button; 55 | 56 | @end 57 | 58 | NS_ASSUME_NONNULL_END 59 | 60 | #endif 61 | 62 | #endif 63 | 64 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Submitting an Issue 2 | 3 | Before you submit your issue please search the issue archive 4 | 5 | If your issue appears to be a bug, providing the following information will increase the chances of your issue being dealt with quickly: 6 | 7 | - Overview of the Issue - if an error is being thrown a non-minified stack trace helps 8 | - Motivation for or Use Case - explain why this is a bug for you 9 | - Browsers and Operating System - is this a problem with all browsers or only specific ones? 10 | - Reproduce the Error - provide a live example 11 | - Related Issues - has a similar issue been reported before? 12 | - Suggest a Fix - if you can't fix the bug yourself, perhaps you can point to what might be causing the problem (line of code or commit) 13 | 14 | 15 | ## Submitting a Pull Request 16 | ### Testing 17 | 18 | Ensure every new module has sufficient testing in place, ideally aiming for 100% coverage where possible. 19 | You are able to see coverage by running 20 | `yarn test:unit - --coverage` 21 | 22 | 23 | Where appropriate (i.e. new features) there should also be a new e2e example created in `*.fructose.@(web|ios|android).js`. 24 | 25 | On submitting a PR all unit, integration and e2e tests will run. If a failure occurs your PR will not be approved. 26 | 27 | ### Commit messages 28 | 29 | When committing please follow the set convention below: 30 | 31 | ``` 32 | feat: A new feature 33 | fix: A bug fix 34 | docs: Documentation only changes 35 | style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc) 36 | refactor: A code change that neither fixes a bug nor adds a feature 37 | perf: A code change that improves performance 38 | test: Adding missing or correcting existing tests 39 | chore: Changes to the build process or auxiliary tools and libraries such as documentation generation 40 | ``` 41 | 42 | Fructose uses an auto publishing feature that uses this commit convention to work out the bump version. 43 | 44 | [detox]: https://github.com/wix/detox/blob/master/docs/Introduction.GettingStarted.md 45 | -------------------------------------------------------------------------------- /ios/e2eTests.app/Frameworks/XCTest.framework/Headers/XCTestCaseRun.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2013-2015 Apple Inc. All rights reserved. 3 | // 4 | // Copyright (c) 1997-2005, Sen:te (Sente SA). All rights reserved. 5 | // 6 | // Use of this source code is governed by the following license: 7 | // 8 | // Redistribution and use in source and binary forms, with or without modification, 9 | // are permitted provided that the following conditions are met: 10 | // 11 | // (1) Redistributions of source code must retain the above copyright notice, 12 | // this list of conditions and the following disclaimer. 13 | // 14 | // (2) Redistributions in binary form must reproduce the above copyright notice, 15 | // this list of conditions and the following disclaimer in the documentation 16 | // and/or other materials provided with the distribution. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 19 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 | // IN NO EVENT SHALL Sente SA OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 23 | // OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 | // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 26 | // EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | // Note: this license is equivalent to the FreeBSD license. 29 | // 30 | // This notice may not be removed from this file. 31 | 32 | #import 33 | 34 | NS_ASSUME_NONNULL_BEGIN 35 | 36 | @class XCTestCase; 37 | 38 | @interface XCTestCaseRun : XCTestRun 39 | 40 | - (void)recordFailureInTest:(XCTestCase *)testCase withDescription:(NSString *)description inFile:(NSString *)filePath atLine:(NSUInteger)lineNumber expected:(BOOL)expected DEPRECATED_ATTRIBUTE; 41 | 42 | @end 43 | 44 | NS_ASSUME_NONNULL_END 45 | -------------------------------------------------------------------------------- /ios/e2eTests.app/Frameworks/XCTest.framework/Headers/XCTestSuiteRun.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2013-2015 Apple Inc. All rights reserved. 3 | // 4 | // Copyright (c) 1997-2005, Sen:te (Sente SA). All rights reserved. 5 | // 6 | // Use of this source code is governed by the following license: 7 | // 8 | // Redistribution and use in source and binary forms, with or without modification, 9 | // are permitted provided that the following conditions are met: 10 | // 11 | // (1) Redistributions of source code must retain the above copyright notice, 12 | // this list of conditions and the following disclaimer. 13 | // 14 | // (2) Redistributions in binary form must reproduce the above copyright notice, 15 | // this list of conditions and the following disclaimer in the documentation 16 | // and/or other materials provided with the distribution. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 19 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 | // IN NO EVENT SHALL Sente SA OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 23 | // OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 | // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 26 | // EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | // Note: this license is equivalent to the FreeBSD license. 29 | // 30 | // This notice may not be removed from this file. 31 | 32 | #import 33 | 34 | NS_ASSUME_NONNULL_BEGIN 35 | 36 | @interface XCTestSuiteRun : XCTestRun { 37 | #ifndef __OBJC2__ 38 | @private 39 | NSMutableArray *_testRuns; 40 | #endif 41 | } 42 | 43 | @property (readonly, copy) NSArray *testRuns; 44 | 45 | - (void)addTestRun:(XCTestRun *)testRun; 46 | 47 | @end 48 | 49 | NS_ASSUME_NONNULL_END 50 | -------------------------------------------------------------------------------- /ios/e2eTests.app/Frameworks/XCTest.framework/Headers/XCTDarwinNotificationExpectation.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016 Apple Inc. All rights reserved. 3 | // 4 | 5 | #import 6 | #import 7 | #import 8 | 9 | NS_ASSUME_NONNULL_BEGIN 10 | 11 | /*! 12 | * @typedef 13 | * Handler called when the expectation has received the Darwin notification. If the handler is not 14 | * provided the first posting of the notification will fulfill the expectation. If provided, the handler 15 | * will be queried each time the notification is received to determine whether the expectation should 16 | * be fulfilled or not. This allows the caller to check Darwin state variables or perform other logic 17 | * beyond simply verifying that the notification has been posted. 18 | */ 19 | typedef BOOL (^XCTDarwinNotificationExpectationHandler)(); 20 | 21 | /*! 22 | * @class XCTDarwinNotificationExpectation 23 | * Expectation subclass for waiting on a condition defined by a Darwin notification. The notification 24 | * which may be posted in the same process or by other processes. 25 | */ 26 | @interface XCTDarwinNotificationExpectation : XCTestExpectation { 27 | #ifndef __OBJC2__ 28 | @private 29 | id _internal; 30 | #endif 31 | } 32 | 33 | - (instancetype)init NS_UNAVAILABLE; 34 | - (instancetype)initWithDescription:(NSString *)expectationDescription NS_UNAVAILABLE; 35 | 36 | /*! 37 | * @method -initWithNotificationName: 38 | * 39 | * @discussion 40 | * Initializes an expectation that waits for a Darwin notification to be posted. 41 | */ 42 | - (instancetype)initWithNotificationName:(NSString *)notificationName NS_DESIGNATED_INITIALIZER; 43 | 44 | /*! 45 | * @property notificationName 46 | * Returns the value of the notification name that was provided to the initializer. 47 | */ 48 | @property (readonly, copy) NSString *notificationName; 49 | 50 | /*! 51 | * @property handler 52 | * Allows the caller to install a special handler to do custom evaluation when the notification is posted. 53 | */ 54 | @property (nullable, copy) XCTDarwinNotificationExpectationHandler handler; 55 | 56 | @end 57 | 58 | NS_ASSUME_NONNULL_END 59 | -------------------------------------------------------------------------------- /packages/web/bin/start.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | const program = require("commander"); 3 | const log = require("../../common/logger"); 4 | 5 | program 6 | .version("0.0.1") 7 | .option( 8 | "-d, --build-dir [directory]", 9 | "specify the directory where webpack.config.js lives" 10 | ) 11 | .parse(process.argv); 12 | 13 | if (!program.buildDir) 14 | throw new Error( 15 | "you must define the build directory: --build-dir [directory]" 16 | ); 17 | 18 | const merge = require("webpack-merge"); 19 | const webpack = require("webpack"); 20 | const WebpackDevServer = require("webpack-dev-server"); 21 | const path = require("path"); 22 | 23 | const directory = path.resolve(program.buildDir); 24 | 25 | // eslint-disable-next-line import/no-dynamic-require 26 | const upperConfig = require(`${directory}/webpack.config.js`); 27 | const config = require("../webpack.config.js"); 28 | 29 | const mergedConfig = merge(config, upperConfig); 30 | const fs = require("fs"); 31 | 32 | function getHeadHtml(configDirPath) { 33 | const headHtmlPath = path.resolve(configDirPath, "head.html"); 34 | let headHtml = ""; 35 | if (fs.existsSync(headHtmlPath)) { 36 | headHtml = fs.readFileSync(headHtmlPath, "utf8"); 37 | } 38 | return headHtml; 39 | } 40 | 41 | const headHtml = getHeadHtml(directory); 42 | const ejsTemplate = ` 43 | 44 | 45 | 46 | 47 | React Native Web 48 | 49 | 50 | ${headHtml} 51 | 52 | 53 |
54 | 55 | 56 | `; 57 | 58 | fs.writeFileSync(path.join(__dirname, "../index.ejs"), ejsTemplate); 59 | 60 | new WebpackDevServer(webpack(mergedConfig), { 61 | publicPath: mergedConfig.output.publicPath, 62 | contentBase: mergedConfig.output.path, 63 | hot: false, 64 | historyApiFallback: true 65 | }).listen( 66 | 3000, 67 | "localhost", 68 | err => 69 | err 70 | ? log.info("web-start", err) 71 | : log.info("web-start", "Listening at http://localhost:3000/") 72 | ); 73 | -------------------------------------------------------------------------------- /packages/app/src/components/navigation/__snapshots__/navigationHeader.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Navigation Header Renders with back icon 1`] = ` 4 | 8 | 19 | 32 | 44 | Component List 45 | 46 | 47 | 48 | 49 | `; 50 | 51 | exports[`Navigation Header Renders without back icon 1`] = ` 52 | 56 | 67 | 75 | 87 | Component List 88 | 89 | 90 | 91 | 92 | `; 93 | -------------------------------------------------------------------------------- /ios/e2eTests.app/Frameworks/XCTest.framework/Headers/XCTestObservationCenter.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2013-2015 Apple Inc. All rights reserved. 3 | // 4 | 5 | #import 6 | 7 | #import 8 | 9 | NS_ASSUME_NONNULL_BEGIN 10 | 11 | /*! 12 | * @class XCTestObservationCenter 13 | * 14 | * The XCTestObservationCenter distributes information about the progress of test runs to registered 15 | * observers. Observers can be any object conforming to the XCTestObservation protocol. 16 | * 17 | * If an NSPrincipalClass is declared in the test bundle's Info.plist, XCTest automatically creates a 18 | * single instance of that class when the test bundle is loaded. This instance provides a means to register 19 | * observers or do other pretesting global set up. 20 | * 21 | * Observers must be registered manually. The NSPrincipalClass instance is not automatically 22 | * registered as an observer even if the class conforms to . 23 | */ 24 | @interface XCTestObservationCenter : NSObject { 25 | #ifndef __OBJC2__ 26 | @private 27 | id _internalImplementation; 28 | #endif 29 | } 30 | 31 | /*! 32 | * @method +sharedTestObservationCenter 33 | * 34 | * @return The shared XCTestObservationCenter singleton instance. 35 | */ 36 | + (XCTestObservationCenter *)sharedTestObservationCenter; 37 | 38 | /*! 39 | * @method -addTestObserver: 40 | * 41 | * Register an object conforming to XCTestObservation as an observer for the current test session. Observers may be added 42 | * at any time, but will not receive events that occurred before they were registered. The observation center maintains a strong 43 | * reference to observers. 44 | * 45 | * Events may be delivered to observers in any order - given observers A and B, A may be notified of a test failure before 46 | * or after B. Any ordering dependencies or serialization requirements must be managed by clients. 47 | */ 48 | - (void)addTestObserver:(id )testObserver; 49 | 50 | /*! 51 | * @method -removeTestObserver: 52 | * 53 | * Unregister an object conforming to XCTestObservation as an observer for the current test session. 54 | */ 55 | - (void)removeTestObserver:(id )testObserver; 56 | 57 | @end 58 | 59 | NS_ASSUME_NONNULL_END 60 | -------------------------------------------------------------------------------- /ios/e2eTests.app/Frameworks/XCTest.framework/Headers/XCTestLog.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2013-2015 Apple Inc. All rights reserved. 3 | // 4 | // Copyright (c) 1997-2005, Sen:te (Sente SA). All rights reserved. 5 | // 6 | // Use of this source code is governed by the following license: 7 | // 8 | // Redistribution and use in source and binary forms, with or without modification, 9 | // are permitted provided that the following conditions are met: 10 | // 11 | // (1) Redistributions of source code must retain the above copyright notice, 12 | // this list of conditions and the following disclaimer. 13 | // 14 | // (2) Redistributions in binary form must reproduce the above copyright notice, 15 | // this list of conditions and the following disclaimer in the documentation 16 | // and/or other materials provided with the distribution. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 19 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 | // IN NO EVENT SHALL Sente SA OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 23 | // OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 | // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 26 | // EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | // Note: this license is equivalent to the FreeBSD license. 29 | // 30 | // This notice may not be removed from this file. 31 | 32 | #import 33 | 34 | /*! 35 | * XCTestLog is deprecated. 36 | */ 37 | 38 | DEPRECATED_ATTRIBUTE 39 | #pragma clang diagnostic push 40 | #pragma clang diagnostic ignored "-Wdeprecated-declarations" 41 | @interface XCTestLog : XCTestObserver 42 | #pragma clang diagnostic pop 43 | 44 | @property (readonly, strong) NSFileHandle *logFileHandle; 45 | - (void)testLogWithFormat:(NSString *)format, ... NS_FORMAT_FUNCTION(1,2); 46 | - (void)testLogWithFormat:(NSString *)format arguments:(va_list)arguments NS_FORMAT_FUNCTION(1,0); 47 | 48 | @end 49 | 50 | -------------------------------------------------------------------------------- /ios/e2eTestsTests/e2eTestsTests.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import 11 | #import 12 | 13 | #import 14 | #import 15 | 16 | #define TIMEOUT_SECONDS 600 17 | #define TEXT_TO_LOOK_FOR @"Welcome to React Native!" 18 | 19 | @interface e2eTestsTests : XCTestCase 20 | 21 | @end 22 | 23 | @implementation e2eTestsTests 24 | 25 | - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test 26 | { 27 | if (test(view)) { 28 | return YES; 29 | } 30 | for (UIView *subview in [view subviews]) { 31 | if ([self findSubviewInView:subview matching:test]) { 32 | return YES; 33 | } 34 | } 35 | return NO; 36 | } 37 | 38 | - (void)testRendersWelcomeScreen 39 | { 40 | UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController]; 41 | NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS]; 42 | BOOL foundElement = NO; 43 | 44 | __block NSString *redboxError = nil; 45 | RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) { 46 | if (level >= RCTLogLevelError) { 47 | redboxError = message; 48 | } 49 | }); 50 | 51 | while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) { 52 | [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 53 | [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 54 | 55 | foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) { 56 | if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { 57 | return YES; 58 | } 59 | return NO; 60 | }]; 61 | } 62 | 63 | RCTSetLogFunction(RCTDefaultLogFunction); 64 | 65 | XCTAssertNil(redboxError, @"RedBox error: %@", redboxError); 66 | XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS); 67 | } 68 | 69 | 70 | @end 71 | -------------------------------------------------------------------------------- /packages/server/index.test.js: -------------------------------------------------------------------------------- 1 | /* globals describe it afterEach expect */ 2 | 3 | const { FructoseServer } = require("./index"); 4 | const client = require("socket.io-client"); 5 | const portfinder = require("portfinder"); 6 | 7 | describe("FructoseServer", () => { 8 | let server; 9 | let PORT; 10 | let socket; 11 | const socketConfig = { 12 | transports: ["websocket"], 13 | query: { 14 | clientType: "tests" 15 | } 16 | }; 17 | 18 | const setUp = config => 19 | portfinder 20 | .getPortPromise() 21 | .then(port => { 22 | PORT = port; 23 | server = new FructoseServer(PORT); 24 | socket = client(`http://localhost:${PORT}`, config); 25 | }) 26 | .then(() => server.start()); 27 | 28 | afterEach(async () => { 29 | await socket.disconnect(); 30 | await server.close(); 31 | }); 32 | 33 | it("forwards the load-component-in-app message", done => { 34 | setUp(socketConfig).then(() => { 35 | socket.on("load-component-in-app", x => { 36 | expect(x).toBe("a component"); 37 | done(); 38 | }); 39 | socket.emit("load-component-in-app", "a component"); 40 | }); 41 | }); 42 | 43 | it("forwards the fructose-app-ready message", done => { 44 | setUp(socketConfig).then(() => { 45 | socket.on("fructose-app-ready", () => { 46 | done(); 47 | }); 48 | 49 | socket.emit("fructose-app-ready"); 50 | }); 51 | }); 52 | 53 | it("forwards the component-loaded-in-app message", done => { 54 | setUp(socketConfig).then(() => { 55 | socket.on("component-loaded-in-app", () => { 56 | done(); 57 | }); 58 | 59 | socket.emit("component-loaded-in-app"); 60 | }); 61 | }); 62 | 63 | it("forwards the get-loaded-app-components", () => 64 | new Promise(resolve => { 65 | setUp(socketConfig).then(() => { 66 | socket.on("get-loaded-app-components", () => { 67 | resolve(); 68 | }); 69 | 70 | socket.emit("get-loaded-app-components"); 71 | }); 72 | })); 73 | 74 | it("forwards the bundled-components", () => 75 | new Promise(resolve => { 76 | setUp(socketConfig).then(() => { 77 | socket.on("send-loaded-app-components", () => { 78 | resolve(); 79 | }); 80 | 81 | socket.emit("send-loaded-app-components"); 82 | }); 83 | })); 84 | }); 85 | -------------------------------------------------------------------------------- /ios/e2eTests.app/Frameworks/XCTest.framework/Headers/XCUIApplication.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2014-2015 Apple Inc. All rights reserved. 3 | // 4 | 5 | #import 6 | #import 7 | 8 | NS_ASSUME_NONNULL_BEGIN 9 | 10 | #if XCT_UI_TESTING_AVAILABLE 11 | 12 | NS_CLASS_AVAILABLE(10_11, 9_0) 13 | 14 | /*! Proxy for an application. The information identifying the application is specified in the Xcode target settings as the "Target Application". */ 15 | @interface XCUIApplication : XCUIElement 16 | 17 | /*! 18 | * Launches the application. This call is synchronous and when it returns the application is launched 19 | * and ready to handle user events. Any failure in the launch sequence is reported as a test failure 20 | * and halts the test at this point. If the application is already running, this call will first 21 | * terminate the existing instance to ensure clean state of the launched instance. 22 | */ 23 | - (void)launch; 24 | 25 | /*! 26 | * Terminates any running instance of the application. If the application has an existing debug session 27 | * via Xcode, the termination is implemented as a halt via that debug connection. Otherwise, a SIGKILL 28 | * is sent to the process. 29 | */ 30 | - (void)terminate; 31 | 32 | /*! 33 | * The arguments that will be passed to the application on launch. If not modified, these are the 34 | * arguments that Xcode will pass on launch. Those arguments can be changed, added to, or removed. 35 | * Unlike NSTask, it is legal to modify these arguments after the application has been launched. These 36 | * changes will not affect the current launch session, but will take effect the next time the application 37 | * is launched. 38 | */ 39 | @property (nonatomic, copy) NSArray *launchArguments; 40 | 41 | /*! 42 | * The environment that will be passed to the application on launch. If not modified, this is the 43 | * environment that Xcode will pass on launch. Those variables can be changed, added to, or removed. 44 | * Unlike NSTask, it is legal to modify the environment after the application has been launched. These 45 | * changes will not affect the current launch session, but will take effect the next time the application 46 | * is launched. 47 | */ 48 | @property (nonatomic, copy) NSDictionary *launchEnvironment; 49 | 50 | @end 51 | 52 | #endif 53 | 54 | NS_ASSUME_NONNULL_END 55 | -------------------------------------------------------------------------------- /ios/e2eTests.app/Frameworks/XCTest.framework/Headers/XCTestProbe.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2013-2015 Apple Inc. All rights reserved. 3 | // 4 | // Copyright (c) 1997-2005, Sen:te (Sente SA). All rights reserved. 5 | // 6 | // Use of this source code is governed by the following license: 7 | // 8 | // Redistribution and use in source and binary forms, with or without modification, 9 | // are permitted provided that the following conditions are met: 10 | // 11 | // (1) Redistributions of source code must retain the above copyright notice, 12 | // this list of conditions and the following disclaimer. 13 | // 14 | // (2) Redistributions in binary form must reproduce the above copyright notice, 15 | // this list of conditions and the following disclaimer in the documentation 16 | // and/or other materials provided with the distribution. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 19 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 | // IN NO EVENT SHALL Sente SA OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 23 | // OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 | // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 26 | // EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | // Note: this license is equivalent to the FreeBSD license. 29 | // 30 | // This notice may not be removed from this file. 31 | 32 | #import 33 | 34 | #import 35 | 36 | XCT_EXPORT int XCTSelfTestMain(void) DEPRECATED_ATTRIBUTE; 37 | 38 | DEPRECATED_ATTRIBUTE 39 | @interface XCTestProbe : NSObject 40 | 41 | + (BOOL)isTesting; 42 | 43 | @end 44 | 45 | XCT_EXPORT NSString * const XCTestedUnitPath DEPRECATED_ATTRIBUTE; 46 | XCT_EXPORT NSString * const XCTestScopeKey DEPRECATED_ATTRIBUTE; 47 | XCT_EXPORT NSString * const XCTestScopeAll DEPRECATED_ATTRIBUTE; 48 | XCT_EXPORT NSString * const XCTestScopeNone DEPRECATED_ATTRIBUTE; 49 | XCT_EXPORT NSString * const XCTestScopeSelf DEPRECATED_ATTRIBUTE; 50 | XCT_EXPORT NSString * const XCTestToolKey DEPRECATED_ATTRIBUTE; 51 | -------------------------------------------------------------------------------- /ios/e2eTests.app/Frameworks/XCTest.framework/Headers/XCTNSNotificationExpectation.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016 Apple Inc. All rights reserved. 3 | // 4 | 5 | #import 6 | #import 7 | #import 8 | 9 | NS_ASSUME_NONNULL_BEGIN 10 | 11 | /*! 12 | * @class XCTNSNotificationExpectation 13 | * Expectation subclass for waiting on a condition defined by an NSNotification. 14 | */ 15 | @interface XCTNSNotificationExpectation : XCTestExpectation { 16 | #ifndef __OBJC2__ 17 | @private 18 | id _internal; 19 | #endif 20 | } 21 | 22 | - (instancetype)init NS_UNAVAILABLE; 23 | - (instancetype)initWithDescription:(NSString *)expectationDescription NS_UNAVAILABLE; 24 | 25 | /*! 26 | * @method -initWithName:object:notificationCenter: 27 | * 28 | * @discussion 29 | * Initializes an expectation that waits for an NSNotification to be posted by an optional object from 30 | * a given notification center. 31 | */ 32 | - (instancetype)initWithName:(NSString *)notificationName object:(nullable id)object notificationCenter:(NSNotificationCenter *)notificationCenter NS_DESIGNATED_INITIALIZER; 33 | 34 | /*! 35 | * @method -initWithName:object: 36 | * 37 | * @discussion 38 | * Convenience initializer that uses the default NSNotificationCenter. 39 | */ 40 | - (instancetype)initWithName:(NSString *)notificationName object:(id)object; 41 | 42 | /*! 43 | * @method -initWithName:object: 44 | * 45 | * @discussion 46 | * Convenience initializer that uses the default NSNotificationCenter and accepts the notification from any object. 47 | */ 48 | - (instancetype)initWithName:(NSString *)notificationName; 49 | 50 | /*! 51 | * @property notificationName 52 | * Returns the name of the notification being waited on. 53 | */ 54 | @property (readonly, copy) NSString *notificationName; 55 | 56 | /*! 57 | * @property observedObject 58 | * Returns the object that will post the notification. 59 | */ 60 | @property (nullable, readonly, strong) id observedObject; 61 | 62 | /*! 63 | * @property notificationCenter 64 | * Returns the notification center that is being used. 65 | */ 66 | @property (readonly, strong) NSNotificationCenter *notificationCenter; 67 | 68 | /*! 69 | * @property handler 70 | * Allows the caller to install a special handler to do custom evaluation of received notifications 71 | * matching the specified object and notification center. 72 | */ 73 | @property (nullable, copy) XCNotificationExpectationHandler handler; 74 | 75 | @end 76 | 77 | NS_ASSUME_NONNULL_END 78 | -------------------------------------------------------------------------------- /packages/client/client.test.js: -------------------------------------------------------------------------------- 1 | /* globals describe it expect beforeAll afterEach */ 2 | const Client = require("./client"); 3 | const express = require("express"); 4 | const http = require("http"); 5 | const socketio = require("socket.io"); 6 | const SocketClient = require("socket.io-client"); 7 | 8 | describe("Fructose Client", () => { 9 | let app; 10 | let socketClient; 11 | let fructose; 12 | let server; 13 | let io; 14 | 15 | beforeAll(() => { 16 | app = express(); 17 | server = http.Server(app); 18 | io = socketio(server); 19 | }); 20 | 21 | afterEach(() => { 22 | fructose.disconnect(); 23 | io.close(); 24 | server.close(); 25 | }); 26 | 27 | it("waits for the app to load", () => 28 | new Promise(resolve => { 29 | io.on("connection", () => { 30 | io.emit("fructose-app-ready"); 31 | }); 32 | 33 | server.listen(0, async () => { 34 | const { port } = server.address(); 35 | socketClient = SocketClient(`http://localhost:${port}`); 36 | fructose = new Client(socketClient); 37 | await fructose.waitForApp(); 38 | resolve(); 39 | }); 40 | })); 41 | 42 | it("can load a component", () => 43 | new Promise(resolve => { 44 | io.on("connection", socket => { 45 | socket.on("load-component-in-app", x => { 46 | expect(x).toBe("component"); 47 | io.emit("component-loaded-in-app"); 48 | }); 49 | }); 50 | 51 | server.listen(0, () => { 52 | const { port } = server.address(); 53 | socketClient = SocketClient(`http://localhost:${port}`); 54 | fructose = new Client(socketClient); 55 | expect(fructose.loadComponent("component")) 56 | .resolves.toBe("component loaded") 57 | .then(resolve); 58 | }); 59 | })); 60 | 61 | it("returns a list of components loaded in the app", () => 62 | new Promise(resolve => { 63 | const componentList = ["a", "b", "c"]; 64 | 65 | io.on("connection", socket => { 66 | socket.on("get-loaded-app-components", () => { 67 | io.emit("send-loaded-app-components", componentList); 68 | }); 69 | }); 70 | 71 | server.listen(0, () => { 72 | const { port } = server.address(); 73 | socketClient = SocketClient(`http://localhost:${port}`); 74 | fructose = new Client(socketClient); 75 | expect(fructose.getLoadedComponents()) 76 | .resolves.toMatchObject(componentList) 77 | .then(resolve); 78 | }); 79 | })); 80 | }); 81 | -------------------------------------------------------------------------------- /ios/e2eTests.app/Frameworks/XCTest.framework/Headers/XCTestObserver.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2013-2015 Apple Inc. All rights reserved. 3 | // 4 | // Copyright (c) 1997-2005, Sen:te (Sente SA). All rights reserved. 5 | // 6 | // Use of this source code is governed by the following license: 7 | // 8 | // Redistribution and use in source and binary forms, with or without modification, 9 | // are permitted provided that the following conditions are met: 10 | // 11 | // (1) Redistributions of source code must retain the above copyright notice, 12 | // this list of conditions and the following disclaimer. 13 | // 14 | // (2) Redistributions in binary form must reproduce the above copyright notice, 15 | // this list of conditions and the following disclaimer in the documentation 16 | // and/or other materials provided with the distribution. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 19 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 | // IN NO EVENT SHALL Sente SA OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 23 | // OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 | // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 26 | // EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | // Note: this license is equivalent to the FreeBSD license. 29 | // 30 | // This notice may not be removed from this file. 31 | 32 | #import 33 | 34 | @class XCTestRun; 35 | 36 | /*! 37 | * XCTestObserver is deprecated. 38 | */ 39 | DEPRECATED_ATTRIBUTE 40 | @interface XCTestObserver : NSObject 41 | 42 | - (void)startObserving; 43 | - (void)stopObserving; 44 | - (void)testSuiteDidStart:(XCTestRun *)testRun; 45 | - (void)testSuiteDidStop:(XCTestRun *)testRun; 46 | - (void)testCaseDidStart:(XCTestRun *)testRun; 47 | - (void)testCaseDidStop:(XCTestRun *)testRun; 48 | - (void)testCaseDidFail:(XCTestRun *)testRun withDescription:(NSString *)description inFile:(NSString *)filePath atLine:(NSUInteger)lineNumber; 49 | 50 | @end 51 | 52 | /*! 53 | * XCTestObserverClassKey is deprecated and ignored. 54 | */ 55 | XCT_EXPORT NSString * const XCTestObserverClassKey DEPRECATED_ATTRIBUTE; 56 | -------------------------------------------------------------------------------- /ios/e2eTests.app/Frameworks/XCTest.framework/Headers/XCTestDefines.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2013-2015 Apple Inc. All rights reserved. 3 | // 4 | // Copyright (c) 1997-2005, Sen:te (Sente SA). All rights reserved. 5 | // 6 | // Use of this source code is governed by the following license: 7 | // 8 | // Redistribution and use in source and binary forms, with or without modification, 9 | // are permitted provided that the following conditions are met: 10 | // 11 | // (1) Redistributions of source code must retain the above copyright notice, 12 | // this list of conditions and the following disclaimer. 13 | // 14 | // (2) Redistributions in binary form must reproduce the above copyright notice, 15 | // this list of conditions and the following disclaimer in the documentation 16 | // and/or other materials provided with the distribution. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 19 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 | // IN NO EVENT SHALL Sente SA OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 23 | // OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 | // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 26 | // EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | // Note: this license is equivalent to the FreeBSD license. 29 | // 30 | // This notice may not be removed from this file. 31 | 32 | #import 33 | 34 | #if defined(__cplusplus) 35 | #define XCT_EXPORT extern "C" 36 | #else 37 | #define XCT_EXPORT extern 38 | #endif 39 | 40 | #if defined(__OBJC2__) && __OBJC2__ 41 | #ifndef XCT_UI_TESTING_AVAILABLE 42 | #define XCT_UI_TESTING_AVAILABLE 1 43 | #endif 44 | #endif 45 | 46 | #ifndef XCT_UI_TESTING_AVAILABLE 47 | #define XCT_UI_TESTING_AVAILABLE 0 48 | #endif 49 | 50 | #if TARGET_OS_SIMULATOR 51 | #define XCTEST_SIMULATOR_UNAVAILABLE(_msg) __attribute__((availability(ios,unavailable,message=_msg))) 52 | #else 53 | #define XCTEST_SIMULATOR_UNAVAILABLE(_msg) 54 | #endif 55 | 56 | #if __has_attribute(warn_unused_result) 57 | #define XCT_WARN_UNUSED __attribute__((__warn_unused_result__)) 58 | #else 59 | #define XCT_WARN_UNUSED 60 | #endif 61 | -------------------------------------------------------------------------------- /ios/e2eTests.app/Frameworks/XCTest.framework/Headers/XCUIElementAttributes.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2015 Apple Inc. All rights reserved. 3 | // 4 | 5 | #import 6 | #import 7 | 8 | #if XCT_UI_TESTING_AVAILABLE 9 | 10 | #if TARGET_OS_IPHONE 11 | 12 | #import 13 | 14 | typedef NS_ENUM(NSInteger, XCUIUserInterfaceSizeClass) { 15 | XCUIUserInterfaceSizeClassUnspecified = UIUserInterfaceSizeClassUnspecified, 16 | XCUIUserInterfaceSizeClassCompact = UIUserInterfaceSizeClassCompact, 17 | XCUIUserInterfaceSizeClassRegular = UIUserInterfaceSizeClassRegular, 18 | }; 19 | 20 | #else 21 | 22 | #import 23 | 24 | typedef NS_ENUM(NSInteger, XCUIUserInterfaceSizeClass) { 25 | XCUIUserInterfaceSizeClassUnspecified = 0, 26 | }; 27 | 28 | #endif 29 | 30 | NS_ASSUME_NONNULL_BEGIN 31 | 32 | /*! Protocol describing the attributes exposed on user interface elements and available during query matching. These attributes represent data exposed to the Accessibility system. */ 33 | @protocol XCUIElementAttributes 34 | 35 | /*! The accessibility identifier. */ 36 | @property (readonly) NSString *identifier; 37 | 38 | /*! The frame of the element in the screen coordinate space. */ 39 | @property (readonly) CGRect frame; 40 | 41 | /*! The raw value attribute of the element. Depending on the element, the actual type can vary. */ 42 | @property (readonly, nullable) id value; 43 | 44 | /*! The title attribute of the element. */ 45 | @property (readonly, copy) NSString *title; 46 | 47 | /*! The label attribute of the element. */ 48 | @property (readonly, copy) NSString *label; 49 | 50 | /*! The type of the element. /seealso XCUIElementType. */ 51 | @property (readonly) XCUIElementType elementType; 52 | 53 | /*! Whether or not the element is enabled for user interaction. */ 54 | @property (readonly, getter = isEnabled) BOOL enabled; 55 | 56 | /*! The horizontal size class of the element. */ 57 | @property (readonly) XCUIUserInterfaceSizeClass horizontalSizeClass; 58 | 59 | /*! The vertical size class of the element. */ 60 | @property (readonly) XCUIUserInterfaceSizeClass verticalSizeClass; 61 | 62 | /*! The value that is displayed when the element has no value. */ 63 | @property (readonly, nullable) NSString *placeholderValue; 64 | 65 | /*! Whether or not the element is selected. */ 66 | @property (readonly, getter = isSelected) BOOL selected; 67 | 68 | #if TARGET_OS_TV 69 | /*! Whether or not the elment has UI focus. */ 70 | @property (readonly) BOOL hasFocus; 71 | #endif 72 | 73 | @end 74 | 75 | NS_ASSUME_NONNULL_END 76 | 77 | #endif 78 | -------------------------------------------------------------------------------- /ios/e2eTests.app/Frameworks/XCTest.framework/Headers/XCTestExpectation.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016 Apple Inc. All rights reserved. 3 | // 4 | 5 | #import 6 | 7 | NS_ASSUME_NONNULL_BEGIN 8 | 9 | /*! 10 | * @class XCTestExpectation 11 | * 12 | * @discussion 13 | * Expectations represent specific conditions in asynchronous testing. 14 | */ 15 | @interface XCTestExpectation : NSObject { 16 | #ifndef __OBJC2__ 17 | id _internalImplementation; 18 | #endif 19 | } 20 | 21 | /*! 22 | * @method -initWithDescription: 23 | * Designated initializer, requires a nonnull description of the condition the expectation is checking. 24 | */ 25 | - (instancetype)initWithDescription:(NSString *)expectationDescription NS_DESIGNATED_INITIALIZER; 26 | 27 | /*! 28 | * @property expectationDescription 29 | * The human readable string used to describe the expectation in log output and test reports. 30 | */ 31 | @property (copy) NSString *expectationDescription; 32 | 33 | /*! 34 | * @property inverted 35 | * If an expectation is set to have inverted behavior, then fulfilling it will have a similar effect that 36 | * failing to fulfill a conventional expectation has, as handled by the waiter and its delegate. Furthermore, 37 | * waiters that wait on an inverted expectation will allow the full timeout to elapse and not report 38 | * timeout to the delegate if it is not fulfilled. 39 | */ 40 | @property (getter=isInverted) BOOL inverted; 41 | 42 | /*! 43 | * @property expectedFulfillmentCount 44 | * The expectedFulfillmentCount is the number of times -fulfill must be called on the expectation in order for it 45 | * to report complete fulfillment to its waiter. By default, expectations have a fufillmentCount of 1. 46 | * This value must be greater than 0 and is not meaningful if combined with @inverted. 47 | */ 48 | @property (nonatomic) NSUInteger expectedFulfillmentCount; 49 | 50 | /*! 51 | * If set, calls to fulfill() after the expectation has already been fulfilled - exceeding the fulfillment 52 | * count - will raise. This is the legacy behavior of expectations created through APIs on XCTestCase 53 | * but is not enabled for expectations created using XCTestExpectation initializers. 54 | */ 55 | @property (nonatomic) BOOL assertForOverFulfill; 56 | 57 | /*! 58 | * @method -fulfill 59 | * 60 | * @discussion 61 | * Call -fulfill to mark an expectation as having been met. It's an error to call 62 | * -fulfill on an expectation that has already been fulfilled or when the test case 63 | * that vended the expectation has already completed. 64 | */ 65 | - (void)fulfill; 66 | 67 | @end 68 | 69 | NS_ASSUME_NONNULL_END 70 | -------------------------------------------------------------------------------- /packages/app/src/components/navigation/navigation.test.js: -------------------------------------------------------------------------------- 1 | /* globals describe beforeEach it expect */ 2 | 3 | import React from "react"; 4 | import express from "express"; 5 | import http from "http"; 6 | import socketio from "socket.io"; 7 | 8 | import { configure, shallow } from "enzyme"; 9 | import Adapter from "enzyme-adapter-react-16"; 10 | import Navigation from "./navigation"; 11 | 12 | configure({ 13 | adapter: new Adapter() 14 | }); 15 | 16 | describe("Navigation", () => { 17 | let app; 18 | let server; 19 | let io; 20 | 21 | beforeAll(() => { 22 | app = express(); 23 | server = http.Server(app); 24 | io = socketio(server); 25 | }); 26 | 27 | beforeEach(done => { 28 | server.listen(7811, done); 29 | }); 30 | 31 | afterEach(() => server.close()); 32 | 33 | it("emits when the app is ready", done => { 34 | app = shallow(); 35 | 36 | io.on("connection", socket => { 37 | socket.on("fructose-app-ready", () => { 38 | done(); 39 | }); 40 | }); 41 | }); 42 | 43 | it("send a list of loaded components in the app", done => { 44 | app = shallow( 45 | 48 | ); 49 | 50 | io.on("connection", socket => { 51 | socket.on("send-loaded-app-components", sentComponents => { 52 | expect(sentComponents).toEqual(["componentloaded", "anothercomponent"]); 53 | done(); 54 | }); 55 | 56 | socket.emit("get-loaded-app-components"); 57 | }); 58 | }); 59 | 60 | it("loads a component in the app", done => { 61 | const navigationMock = { navigate: jest.fn() }; 62 | app = shallow( 63 | 67 | ); 68 | 69 | io.on("connection", socket => { 70 | socket.emit("load-component-in-app", "componentloaded"); 71 | 72 | setTimeout(() => { 73 | expect(navigationMock.navigate).toBeCalledWith("componentloaded"); 74 | done(); 75 | }, 5); 76 | }); 77 | }); 78 | 79 | it("renders when is parent menu", () => { 80 | app = shallow( 81 | 84 | ); 85 | expect(app).toMatchSnapshot(); 86 | }); 87 | 88 | it("renders when is child menu", () => { 89 | app = shallow( 90 | 93 | ); 94 | app.setState({ isParentMenu: false }); 95 | expect(app).toMatchSnapshot(); 96 | }); 97 | }); 98 | -------------------------------------------------------------------------------- /android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /ios/e2eTests.app/Frameworks/XCTest.framework/Headers/XCUIKeyboardKeys.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2015 Apple Inc. All rights reserved. 3 | // 4 | 5 | #import 6 | #import 7 | 8 | #if XCT_UI_TESTING_AVAILABLE 9 | 10 | /*! 11 | Constants for use with -[XCUIElement typeKey:modifierFlags:], 12 | representing keys that have no textual representation. These comprise 13 | the set of control, function, and modifier keys found on most keyboards. 14 | */ 15 | 16 | extern NSString *const XCUIKeyboardKeyDelete; 17 | extern NSString *const XCUIKeyboardKeyReturn; 18 | extern NSString *const XCUIKeyboardKeyEnter; 19 | extern NSString *const XCUIKeyboardKeyTab; 20 | extern NSString *const XCUIKeyboardKeySpace; 21 | extern NSString *const XCUIKeyboardKeyEscape; 22 | 23 | extern NSString *const XCUIKeyboardKeyUpArrow; 24 | extern NSString *const XCUIKeyboardKeyDownArrow; 25 | extern NSString *const XCUIKeyboardKeyLeftArrow; 26 | extern NSString *const XCUIKeyboardKeyRightArrow; 27 | 28 | extern NSString *const XCUIKeyboardKeyF1; 29 | extern NSString *const XCUIKeyboardKeyF2; 30 | extern NSString *const XCUIKeyboardKeyF3; 31 | extern NSString *const XCUIKeyboardKeyF4; 32 | extern NSString *const XCUIKeyboardKeyF5; 33 | extern NSString *const XCUIKeyboardKeyF6; 34 | extern NSString *const XCUIKeyboardKeyF7; 35 | extern NSString *const XCUIKeyboardKeyF8; 36 | extern NSString *const XCUIKeyboardKeyF9; 37 | extern NSString *const XCUIKeyboardKeyF10; 38 | extern NSString *const XCUIKeyboardKeyF11; 39 | extern NSString *const XCUIKeyboardKeyF12; 40 | extern NSString *const XCUIKeyboardKeyF13; 41 | extern NSString *const XCUIKeyboardKeyF14; 42 | extern NSString *const XCUIKeyboardKeyF15; 43 | extern NSString *const XCUIKeyboardKeyF16; 44 | extern NSString *const XCUIKeyboardKeyF17; 45 | extern NSString *const XCUIKeyboardKeyF18; 46 | extern NSString *const XCUIKeyboardKeyF19; 47 | 48 | extern NSString *const XCUIKeyboardKeyForwardDelete; 49 | extern NSString *const XCUIKeyboardKeyHome; 50 | extern NSString *const XCUIKeyboardKeyEnd; 51 | extern NSString *const XCUIKeyboardKeyPageUp; 52 | extern NSString *const XCUIKeyboardKeyPageDown; 53 | extern NSString *const XCUIKeyboardKeyClear; 54 | extern NSString *const XCUIKeyboardKeyHelp; 55 | 56 | extern NSString *const XCUIKeyboardKeyCapsLock; 57 | extern NSString *const XCUIKeyboardKeyShift; 58 | extern NSString *const XCUIKeyboardKeyControl; 59 | extern NSString *const XCUIKeyboardKeyOption; 60 | extern NSString *const XCUIKeyboardKeyCommand; 61 | extern NSString *const XCUIKeyboardKeyRightShift; 62 | extern NSString *const XCUIKeyboardKeyRightControl; 63 | extern NSString *const XCUIKeyboardKeyRightOption; 64 | extern NSString *const XCUIKeyboardKeyRightCommand; 65 | extern NSString *const XCUIKeyboardKeySecondaryFn; 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /ios/e2eTests.app/Frameworks/XCTest.framework/Headers/XCUICoordinate.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2014-2015 Apple Inc. All rights reserved. 3 | // 4 | 5 | #import 6 | 7 | #if TARGET_OS_IPHONE 8 | #import 9 | #else 10 | #import 11 | #endif 12 | 13 | 14 | NS_ASSUME_NONNULL_BEGIN 15 | 16 | #if XCT_UI_TESTING_AVAILABLE && !TARGET_OS_TV 17 | 18 | @class XCUIElement; 19 | 20 | NS_CLASS_AVAILABLE(10_11, 9_0) 21 | 22 | /*! A coordinate represents a location on screen, relative to some element. Coordinates are dynamic, just like the elements to which they refer, and may compute different screen locations at different times, or be invalid if the referenced element does not exist. */ 23 | @interface XCUICoordinate : NSObject 24 | 25 | /*! Coordinates are never instantiated directly. Instead, they are created by elements or by other coordinates. */ 26 | - (instancetype)init NS_UNAVAILABLE; 27 | 28 | /*! The element that the coordinate is based on, either directly or via the coordinate from which it was derived. */ 29 | @property (readonly) XCUIElement *referencedElement; 30 | 31 | /*! The dynamically computed value of the coordinate's location on screen. Note that this value is dependent on the current frame of the referenced element; if the element's frame changes, so will the value returned by this property. If the referenced element does exist when this is called, it will fail the test; check the referenced element's exists property if the element may not be present. */ 32 | @property (readonly) CGPoint screenPoint; 33 | 34 | /*! Creates a new coordinate with an absolute offset in points from the original coordinate. */ 35 | - (XCUICoordinate *)coordinateWithOffset:(CGVector)offsetVector; 36 | 37 | @end 38 | 39 | #if TARGET_OS_IPHONE 40 | 41 | @interface XCUICoordinate (XCUICoordinateTouchEvents) 42 | 43 | - (void)tap; 44 | - (void)doubleTap; 45 | - (void)pressForDuration:(NSTimeInterval)duration; 46 | - (void)pressForDuration:(NSTimeInterval)duration thenDragToCoordinate:(XCUICoordinate *)otherCoordinate; 47 | 48 | @end 49 | 50 | #endif // TARGET_OS_IPHONE 51 | 52 | #if TARGET_OS_OSX 53 | 54 | @interface XCUICoordinate (XCUICoordinateMouseEvents) 55 | 56 | - (void)hover; 57 | - (void)click; 58 | - (void)doubleClick; 59 | - (void)rightClick; 60 | - (void)clickForDuration:(NSTimeInterval)duration thenDragToCoordinate:(XCUICoordinate *)otherCoordinate; 61 | - (void)scrollByDeltaX:(CGFloat)deltaX deltaY:(CGFloat)deltaY; 62 | 63 | @end 64 | 65 | @interface XCUICoordinate (XCUICoordinateTouchBarEvents) 66 | 67 | - (void)tap; 68 | - (void)doubleTap; 69 | - (void)pressForDuration:(NSTimeInterval)duration; 70 | - (void)pressForDuration:(NSTimeInterval)duration thenDragToCoordinate:(XCUICoordinate *)otherCoordinate; 71 | 72 | @end 73 | 74 | #endif // TARGET_OS_OSX 75 | 76 | #endif 77 | 78 | NS_ASSUME_NONNULL_END 79 | -------------------------------------------------------------------------------- /packages/server/index.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const http = require("http"); 3 | const socketio = require("socket.io"); 4 | const enableDestroy = require("server-destroy"); 5 | const log = require("../common/logger"); 6 | 7 | const handleConnectionType = (io, clientType) => { 8 | if (clientType.includes("tests")) { 9 | log.info("server-index", "fructose client connected to Fructose Server"); 10 | } 11 | }; 12 | class FructoseServer { 13 | constructor(port) { 14 | this.app = null; 15 | this.server = null; 16 | this.io = null; 17 | this.i = null; 18 | this.port = port; 19 | } 20 | 21 | close() { 22 | return new Promise(resolve => { 23 | log.info("server-index", "Fructose server terminating"); 24 | this.server.destroy(resolve); 25 | }); 26 | } 27 | 28 | start() { 29 | return new Promise(resolve => { 30 | log.info("server-index", "Fructose Server starting"); 31 | this.app = express(); 32 | this.server = http.Server(this.app); 33 | this.io = socketio(this.server); 34 | 35 | this.app.get("/", (req, res) => { 36 | res.sendFile(`${__dirname}/index.html`); 37 | }); 38 | 39 | this.io.on("connection", socket => { 40 | if (socket.handshake.query.clientType) { 41 | handleConnectionType(this.io, socket.handshake.query.clientType); 42 | } 43 | 44 | socket.on("fructose-app-ready", () => { 45 | this.io.emit("fructose-app-ready"); 46 | }); 47 | 48 | socket.on("load-component-in-app", componentName => { 49 | this.io.emit("load-component-in-app", componentName); 50 | }); 51 | 52 | socket.on("component-loaded-in-app", () => { 53 | this.io.emit("component-loaded-in-app"); 54 | }); 55 | 56 | socket.on("send-loaded-app-components", componentKeys => { 57 | log.verbose( 58 | "server-index", 59 | "Fructose App sending bundled components" 60 | ); 61 | this.io.emit("send-loaded-app-components", componentKeys); 62 | }); 63 | 64 | socket.on("get-loaded-app-components", () => { 65 | this.io.emit("get-loaded-app-components"); 66 | }); 67 | 68 | socket.on("component-error", ({ component, error }) => { 69 | log.error("server-index", `Error found in component: ${component}`); 70 | log.error("server-index", error); 71 | }); 72 | 73 | socket.on("component-not-found", component => { 74 | log.error( 75 | "server-index", 76 | `Error component not found in app: ${component}` 77 | ); 78 | }); 79 | }); 80 | 81 | this.server.listen(this.port, () => { 82 | enableDestroy(this.server); 83 | resolve(); 84 | }); 85 | }); 86 | } 87 | } 88 | 89 | module.exports = { FructoseServer }; 90 | -------------------------------------------------------------------------------- /ios/e2eTests.app/Frameworks/IDEBundleInjection.framework/_CodeSignature/CodeResources: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | files 6 | 7 | Info.plist 8 | 9 | dPPSLt6JHJs4MODwI/naGCfVaCI= 10 | 11 | version.plist 12 | 13 | l5CwN5oWxQMrrcwfwRK++Olu3bw= 14 | 15 | 16 | files2 17 | 18 | version.plist 19 | 20 | l5CwN5oWxQMrrcwfwRK++Olu3bw= 21 | 22 | 23 | rules 24 | 25 | ^ 26 | 27 | ^.*\.lproj/ 28 | 29 | optional 30 | 31 | weight 32 | 1000 33 | 34 | ^.*\.lproj/locversion.plist$ 35 | 36 | omit 37 | 38 | weight 39 | 1100 40 | 41 | ^version.plist$ 42 | 43 | 44 | rules2 45 | 46 | .*\.dSYM($|/) 47 | 48 | weight 49 | 11 50 | 51 | ^ 52 | 53 | weight 54 | 20 55 | 56 | ^(.*/)?\.DS_Store$ 57 | 58 | omit 59 | 60 | weight 61 | 2000 62 | 63 | ^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/ 64 | 65 | nested 66 | 67 | weight 68 | 10 69 | 70 | ^.* 71 | 72 | ^.*\.lproj/ 73 | 74 | optional 75 | 76 | weight 77 | 1000 78 | 79 | ^.*\.lproj/locversion.plist$ 80 | 81 | omit 82 | 83 | weight 84 | 1100 85 | 86 | ^Info\.plist$ 87 | 88 | omit 89 | 90 | weight 91 | 20 92 | 93 | ^PkgInfo$ 94 | 95 | omit 96 | 97 | weight 98 | 20 99 | 100 | ^[^/]+$ 101 | 102 | nested 103 | 104 | weight 105 | 10 106 | 107 | ^embedded\.provisionprofile$ 108 | 109 | weight 110 | 20 111 | 112 | ^version\.plist$ 113 | 114 | weight 115 | 20 116 | 117 | 118 | 119 | 120 | -------------------------------------------------------------------------------- /ios/e2eTests.app/PlugIns/e2eTestsTests.xctest/_CodeSignature/CodeResources: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | files 6 | 7 | Info.plist 8 | 9 | rPai3JVXGQCACNk1J84dr/UFJQc= 10 | 11 | 12 | files2 13 | 14 | rules 15 | 16 | ^ 17 | 18 | ^.*\.lproj/ 19 | 20 | optional 21 | 22 | weight 23 | 1000 24 | 25 | ^.*\.lproj/locversion.plist$ 26 | 27 | omit 28 | 29 | weight 30 | 1100 31 | 32 | ^Base\.lproj/ 33 | 34 | weight 35 | 1010 36 | 37 | ^version.plist$ 38 | 39 | 40 | rules2 41 | 42 | .*\.dSYM($|/) 43 | 44 | weight 45 | 11 46 | 47 | ^ 48 | 49 | weight 50 | 20 51 | 52 | ^(.*/)?\.DS_Store$ 53 | 54 | omit 55 | 56 | weight 57 | 2000 58 | 59 | ^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/ 60 | 61 | nested 62 | 63 | weight 64 | 10 65 | 66 | ^.* 67 | 68 | ^.*\.lproj/ 69 | 70 | optional 71 | 72 | weight 73 | 1000 74 | 75 | ^.*\.lproj/locversion.plist$ 76 | 77 | omit 78 | 79 | weight 80 | 1100 81 | 82 | ^Base\.lproj/ 83 | 84 | weight 85 | 1010 86 | 87 | ^Info\.plist$ 88 | 89 | omit 90 | 91 | weight 92 | 20 93 | 94 | ^PkgInfo$ 95 | 96 | omit 97 | 98 | weight 99 | 20 100 | 101 | ^[^/]+$ 102 | 103 | nested 104 | 105 | weight 106 | 10 107 | 108 | ^embedded\.provisionprofile$ 109 | 110 | weight 111 | 20 112 | 113 | ^version\.plist$ 114 | 115 | weight 116 | 20 117 | 118 | 119 | 120 | 121 | -------------------------------------------------------------------------------- /ios/e2eTests.app/Frameworks/XCTest.framework/XPCServices/XCUIRecorderService.xpc/_CodeSignature/CodeResources: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | files 6 | 7 | Info.plist 8 | 9 | gXl98PRsHnj5lmC2D5fgvPS28To= 10 | 11 | version.plist 12 | 13 | mbsMPuPV++McJcw2lEghJTGkw5g= 14 | 15 | 16 | files2 17 | 18 | version.plist 19 | 20 | mbsMPuPV++McJcw2lEghJTGkw5g= 21 | 22 | 23 | rules 24 | 25 | ^ 26 | 27 | ^.*\.lproj/ 28 | 29 | optional 30 | 31 | weight 32 | 1000 33 | 34 | ^.*\.lproj/locversion.plist$ 35 | 36 | omit 37 | 38 | weight 39 | 1100 40 | 41 | ^version.plist$ 42 | 43 | 44 | rules2 45 | 46 | .*\.dSYM($|/) 47 | 48 | weight 49 | 11 50 | 51 | ^ 52 | 53 | weight 54 | 20 55 | 56 | ^(.*/)?\.DS_Store$ 57 | 58 | omit 59 | 60 | weight 61 | 2000 62 | 63 | ^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/ 64 | 65 | nested 66 | 67 | weight 68 | 10 69 | 70 | ^.* 71 | 72 | ^.*\.lproj/ 73 | 74 | optional 75 | 76 | weight 77 | 1000 78 | 79 | ^.*\.lproj/locversion.plist$ 80 | 81 | omit 82 | 83 | weight 84 | 1100 85 | 86 | ^Info\.plist$ 87 | 88 | omit 89 | 90 | weight 91 | 20 92 | 93 | ^PkgInfo$ 94 | 95 | omit 96 | 97 | weight 98 | 20 99 | 100 | ^[^/]+$ 101 | 102 | nested 103 | 104 | weight 105 | 10 106 | 107 | ^embedded\.provisionprofile$ 108 | 109 | weight 110 | 20 111 | 112 | ^version\.plist$ 113 | 114 | weight 115 | 20 116 | 117 | 118 | 119 | 120 | -------------------------------------------------------------------------------- /ios/e2eTests.app/Frameworks/XCTest.framework/XPCServices/xctestSymbolicator.xpc/_CodeSignature/CodeResources: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | files 6 | 7 | Info.plist 8 | 9 | zUybWWAy9BVyhhwqZrin9j97sy4= 10 | 11 | version.plist 12 | 13 | mbsMPuPV++McJcw2lEghJTGkw5g= 14 | 15 | 16 | files2 17 | 18 | version.plist 19 | 20 | mbsMPuPV++McJcw2lEghJTGkw5g= 21 | 22 | 23 | rules 24 | 25 | ^ 26 | 27 | ^.*\.lproj/ 28 | 29 | optional 30 | 31 | weight 32 | 1000 33 | 34 | ^.*\.lproj/locversion.plist$ 35 | 36 | omit 37 | 38 | weight 39 | 1100 40 | 41 | ^version.plist$ 42 | 43 | 44 | rules2 45 | 46 | .*\.dSYM($|/) 47 | 48 | weight 49 | 11 50 | 51 | ^ 52 | 53 | weight 54 | 20 55 | 56 | ^(.*/)?\.DS_Store$ 57 | 58 | omit 59 | 60 | weight 61 | 2000 62 | 63 | ^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/ 64 | 65 | nested 66 | 67 | weight 68 | 10 69 | 70 | ^.* 71 | 72 | ^.*\.lproj/ 73 | 74 | optional 75 | 76 | weight 77 | 1000 78 | 79 | ^.*\.lproj/locversion.plist$ 80 | 81 | omit 82 | 83 | weight 84 | 1100 85 | 86 | ^Info\.plist$ 87 | 88 | omit 89 | 90 | weight 91 | 20 92 | 93 | ^PkgInfo$ 94 | 95 | omit 96 | 97 | weight 98 | 20 99 | 100 | ^[^/]+$ 101 | 102 | nested 103 | 104 | weight 105 | 10 106 | 107 | ^embedded\.provisionprofile$ 108 | 109 | weight 110 | 20 111 | 112 | ^version\.plist$ 113 | 114 | weight 115 | 20 116 | 117 | 118 | 119 | 120 | -------------------------------------------------------------------------------- /android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Disabling obfuscation is useful if you collect stack traces from production crashes 20 | # (unless you are using a system that supports de-obfuscate the stack traces). 21 | -dontobfuscate 22 | 23 | # React Native 24 | 25 | # Keep our interfaces so they can be used by other ProGuard rules. 26 | # See http://sourceforge.net/p/proguard/bugs/466/ 27 | -keep,allowobfuscation @interface com.facebook.proguard.annotations.DoNotStrip 28 | -keep,allowobfuscation @interface com.facebook.proguard.annotations.KeepGettersAndSetters 29 | -keep,allowobfuscation @interface com.facebook.common.internal.DoNotStrip 30 | 31 | # Do not strip any method/class that is annotated with @DoNotStrip 32 | -keep @com.facebook.proguard.annotations.DoNotStrip class * 33 | -keep @com.facebook.common.internal.DoNotStrip class * 34 | -keepclassmembers class * { 35 | @com.facebook.proguard.annotations.DoNotStrip *; 36 | @com.facebook.common.internal.DoNotStrip *; 37 | } 38 | 39 | -keepclassmembers @com.facebook.proguard.annotations.KeepGettersAndSetters class * { 40 | void set*(***); 41 | *** get*(); 42 | } 43 | 44 | -keep class * extends com.facebook.react.bridge.JavaScriptModule { *; } 45 | -keep class * extends com.facebook.react.bridge.NativeModule { *; } 46 | -keepclassmembers,includedescriptorclasses class * { native ; } 47 | -keepclassmembers class * { @com.facebook.react.uimanager.UIProp ; } 48 | -keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactProp ; } 49 | -keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactPropGroup ; } 50 | 51 | -dontwarn com.facebook.react.** 52 | 53 | # TextLayoutBuilder uses a non-public Android constructor within StaticLayout. 54 | # See libs/proxy/src/main/java/com/facebook/fbui/textlayoutbuilder/proxy for details. 55 | -dontwarn android.text.StaticLayout 56 | 57 | # okhttp 58 | 59 | -keepattributes Signature 60 | -keepattributes *Annotation* 61 | -keep class okhttp3.** { *; } 62 | -keep interface okhttp3.** { *; } 63 | -dontwarn okhttp3.** 64 | 65 | # okio 66 | 67 | -keep class sun.misc.Unsafe { *; } 68 | -dontwarn java.nio.file.* 69 | -dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement 70 | -dontwarn okio.** 71 | -------------------------------------------------------------------------------- /ios/e2eTests.app/Frameworks/XCTest.framework/Headers/XCTest.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2013-2016 Apple Inc. All rights reserved. 3 | // 4 | // Copyright (c) 1997-2005, Sen:te (Sente SA). All rights reserved. 5 | // 6 | // Use of this source code is governed by the following license: 7 | // 8 | // Redistribution and use in source and binary forms, with or without modification, 9 | // are permitted provided that the following conditions are met: 10 | // 11 | // (1) Redistributions of source code must retain the above copyright notice, 12 | // this list of conditions and the following disclaimer. 13 | // 14 | // (2) Redistributions in binary form must reproduce the above copyright notice, 15 | // this list of conditions and the following disclaimer in the documentation 16 | // and/or other materials provided with the distribution. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 19 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 | // IN NO EVENT SHALL Sente SA OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 23 | // OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 | // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 26 | // EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | // Note: this license is equivalent to the FreeBSD license. 29 | // 30 | // This notice may not be removed from this file. 31 | 32 | #import 33 | #import 34 | 35 | #import 36 | #import 37 | #import 38 | #import 39 | #import 40 | #import 41 | #import 42 | #import 43 | #import 44 | #import 45 | #import 46 | #import 47 | #import 48 | #import 49 | #import 50 | #import 51 | #import 52 | #import 53 | #import 54 | #import 55 | 56 | #import 57 | #import 58 | #import 59 | #import 60 | #import 61 | #import 62 | #import 63 | #import 64 | #import 65 | #import 66 | #import 67 | -------------------------------------------------------------------------------- /e2eTests/example/component-pages.showcase.js: -------------------------------------------------------------------------------- 1 | /* globals device test expect element by afterEach beforeEach */ 2 | 3 | import React from "react"; 4 | import { StyleSheet, Text, View } from "react-native"; 5 | 6 | const styles = StyleSheet.create({ 7 | green: { 8 | backgroundColor: "green", 9 | height: "100%", 10 | width: "100%" 11 | }, 12 | aqua: { 13 | backgroundColor: "aqua", 14 | height: "100%", 15 | width: "100%" 16 | }, 17 | blue: { 18 | backgroundColor: "blue", 19 | height: "100%", 20 | width: "100%" 21 | }, 22 | black: { 23 | backgroundColor: "black", 24 | height: "100%", 25 | width: "100%", 26 | color: "white", 27 | fontSize: 100 28 | }, 29 | orange: { 30 | backgroundColor: "orange", 31 | height: "100%", 32 | width: "100%" 33 | }, 34 | purple: { 35 | backgroundColor: "purple", 36 | height: "100%", 37 | width: "100%" 38 | }, 39 | yellow: { 40 | backgroundColor: "yellow", 41 | height: "100%", 42 | width: "100%", 43 | fontSize: 50, 44 | fontWeight: "bold" 45 | } 46 | }); 47 | 48 | const Break = props => { 49 | this.break(); 50 | return ( 51 | 52 | ERROR 53 | 54 | ); 55 | }; 56 | 57 | export default { 58 | name: "Example Pages/Tests", 59 | children: [ 60 | { 61 | type: "story", 62 | name: "The Stone", 63 | component: () => ( 64 | The Philosopher's Stone 65 | ) 66 | }, 67 | { 68 | type: "story", 69 | name: "The Chamber", 70 | component: () => The Chamber of Secrets 71 | }, 72 | { 73 | type: "story", 74 | name: "The Prisoner", 75 | component: () => The Prisoner of Azkaban 76 | }, 77 | { 78 | type: "story", 79 | name: "The Goblet", 80 | component: () => The Goblet of Fire 81 | }, 82 | { 83 | type: "story", 84 | name: "The Order", 85 | component: () => ( 86 | The Order of the Phoenix 87 | ) 88 | }, 89 | { 90 | type: "story", 91 | name: "The Prince", 92 | component: () => The Half Blood Prince 93 | }, 94 | { 95 | type: "story", 96 | name: "The Hallows", 97 | component: () => The Deathly Hallows 98 | }, 99 | { 100 | type: "story", 101 | name: "The Internal JS Error", 102 | component: () => 103 | }, 104 | { 105 | type: "story", 106 | name: "The Handle undefined Knob showcase", 107 | component: ({ undefinedKnob }) => {undefinedKnob()} 108 | }, 109 | { 110 | type: "story", 111 | name: "The Handle knob showcase", 112 | component: ({ e2eTestDontDelete }) => {e2eTestDontDelete()} 113 | } 114 | ] 115 | }; 116 | -------------------------------------------------------------------------------- /e2eTests/example/component-primitives.showcase.js: -------------------------------------------------------------------------------- 1 | /* globals device test expect element by afterEach beforeEach */ 2 | 3 | import React from "react"; 4 | import { StyleSheet, Text, View } from "react-native"; 5 | 6 | const styles = StyleSheet.create({ 7 | green: { 8 | backgroundColor: "green", 9 | height: "100%", 10 | width: "100%" 11 | }, 12 | aqua: { 13 | backgroundColor: "aqua", 14 | height: "100%", 15 | width: "100%" 16 | }, 17 | blue: { 18 | backgroundColor: "blue", 19 | height: "100%", 20 | width: "100%" 21 | }, 22 | black: { 23 | backgroundColor: "black", 24 | height: "100%", 25 | width: "100%", 26 | color: "white", 27 | fontSize: 100 28 | }, 29 | orange: { 30 | backgroundColor: "orange", 31 | height: "100%", 32 | width: "100%" 33 | }, 34 | purple: { 35 | backgroundColor: "purple", 36 | height: "100%", 37 | width: "100%" 38 | }, 39 | yellow: { 40 | backgroundColor: "yellow", 41 | height: "100%", 42 | width: "100%", 43 | fontSize: 50, 44 | fontWeight: "bold" 45 | } 46 | }); 47 | 48 | const Break = props => { 49 | this.break(); 50 | return ( 51 | 52 | ERROR 53 | 54 | ); 55 | }; 56 | 57 | export default { 58 | name: "Example Primitives/Tests", 59 | children: [ 60 | { 61 | type: "story", 62 | name: "The Stone", 63 | component: () => ( 64 | The Philosopher's Stone 65 | ) 66 | }, 67 | { 68 | type: "story", 69 | name: "The Chamber", 70 | component: () => The Chamber of Secrets 71 | }, 72 | { 73 | type: "story", 74 | name: "The Prisoner", 75 | component: () => The Prisoner of Azkaban 76 | }, 77 | { 78 | type: "story", 79 | name: "The Goblet", 80 | component: () => The Goblet of Fire 81 | }, 82 | { 83 | type: "story", 84 | name: "The Order", 85 | component: () => ( 86 | The Order of the Phoenix 87 | ) 88 | }, 89 | { 90 | type: "story", 91 | name: "The Prince", 92 | component: () => The Half Blood Prince 93 | }, 94 | { 95 | type: "story", 96 | name: "The Hallows", 97 | component: () => The Deathly Hallows 98 | }, 99 | { 100 | type: "story", 101 | name: "The Internal JS Error", 102 | component: () => 103 | }, 104 | { 105 | type: "story", 106 | name: "The Handle undefined Knob showcase", 107 | component: ({ undefinedKnob }) => {undefinedKnob()} 108 | }, 109 | { 110 | type: "story", 111 | name: "The Handle knob showcase", 112 | component: ({ e2eTestDontDelete }) => {e2eTestDontDelete()} 113 | } 114 | ] 115 | }; 116 | -------------------------------------------------------------------------------- /ios/e2eTests.app/Frameworks/XCTest.framework/Headers/XCUIElementTypes.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2015 Apple Inc. All rights reserved. 3 | // 4 | 5 | #import 6 | 7 | #if XCT_UI_TESTING_AVAILABLE 8 | 9 | NS_ENUM_AVAILABLE(10_11, 9_0) 10 | typedef NS_ENUM(NSUInteger, XCUIElementType) { 11 | XCUIElementTypeAny = 0, 12 | XCUIElementTypeOther = 1, 13 | XCUIElementTypeApplication = 2, 14 | XCUIElementTypeGroup = 3, 15 | XCUIElementTypeWindow = 4, 16 | XCUIElementTypeSheet = 5, 17 | XCUIElementTypeDrawer = 6, 18 | XCUIElementTypeAlert = 7, 19 | XCUIElementTypeDialog = 8, 20 | XCUIElementTypeButton = 9, 21 | XCUIElementTypeRadioButton = 10, 22 | XCUIElementTypeRadioGroup = 11, 23 | XCUIElementTypeCheckBox = 12, 24 | XCUIElementTypeDisclosureTriangle = 13, 25 | XCUIElementTypePopUpButton = 14, 26 | XCUIElementTypeComboBox = 15, 27 | XCUIElementTypeMenuButton = 16, 28 | XCUIElementTypeToolbarButton = 17, 29 | XCUIElementTypePopover = 18, 30 | XCUIElementTypeKeyboard = 19, 31 | XCUIElementTypeKey = 20, 32 | XCUIElementTypeNavigationBar = 21, 33 | XCUIElementTypeTabBar = 22, 34 | XCUIElementTypeTabGroup = 23, 35 | XCUIElementTypeToolbar = 24, 36 | XCUIElementTypeStatusBar = 25, 37 | XCUIElementTypeTable = 26, 38 | XCUIElementTypeTableRow = 27, 39 | XCUIElementTypeTableColumn = 28, 40 | XCUIElementTypeOutline = 29, 41 | XCUIElementTypeOutlineRow = 30, 42 | XCUIElementTypeBrowser = 31, 43 | XCUIElementTypeCollectionView = 32, 44 | XCUIElementTypeSlider = 33, 45 | XCUIElementTypePageIndicator = 34, 46 | XCUIElementTypeProgressIndicator = 35, 47 | XCUIElementTypeActivityIndicator = 36, 48 | XCUIElementTypeSegmentedControl = 37, 49 | XCUIElementTypePicker = 38, 50 | XCUIElementTypePickerWheel = 39, 51 | XCUIElementTypeSwitch = 40, 52 | XCUIElementTypeToggle = 41, 53 | XCUIElementTypeLink = 42, 54 | XCUIElementTypeImage = 43, 55 | XCUIElementTypeIcon = 44, 56 | XCUIElementTypeSearchField = 45, 57 | XCUIElementTypeScrollView = 46, 58 | XCUIElementTypeScrollBar = 47, 59 | XCUIElementTypeStaticText = 48, 60 | XCUIElementTypeTextField = 49, 61 | XCUIElementTypeSecureTextField = 50, 62 | XCUIElementTypeDatePicker = 51, 63 | XCUIElementTypeTextView = 52, 64 | XCUIElementTypeMenu = 53, 65 | XCUIElementTypeMenuItem = 54, 66 | XCUIElementTypeMenuBar = 55, 67 | XCUIElementTypeMenuBarItem = 56, 68 | XCUIElementTypeMap = 57, 69 | XCUIElementTypeWebView = 58, 70 | XCUIElementTypeIncrementArrow = 59, 71 | XCUIElementTypeDecrementArrow = 60, 72 | XCUIElementTypeTimeline = 61, 73 | XCUIElementTypeRatingIndicator = 62, 74 | XCUIElementTypeValueIndicator = 63, 75 | XCUIElementTypeSplitGroup = 64, 76 | XCUIElementTypeSplitter = 65, 77 | XCUIElementTypeRelevanceIndicator = 66, 78 | XCUIElementTypeColorWell = 67, 79 | XCUIElementTypeHelpTag = 68, 80 | XCUIElementTypeMatte = 69, 81 | XCUIElementTypeDockItem = 70, 82 | XCUIElementTypeRuler = 71, 83 | XCUIElementTypeRulerMarker = 72, 84 | XCUIElementTypeGrid = 73, 85 | XCUIElementTypeLevelIndicator = 74, 86 | XCUIElementTypeCell = 75, 87 | XCUIElementTypeLayoutArea = 76, 88 | XCUIElementTypeLayoutItem = 77, 89 | XCUIElementTypeHandle = 78, 90 | XCUIElementTypeStepper = 79, 91 | XCUIElementTypeTab = 80, 92 | XCUIElementTypeTouchBar = 81 93 | }; 94 | 95 | #endif 96 | -------------------------------------------------------------------------------- /packages/app/src/componentLoader.test.js: -------------------------------------------------------------------------------- 1 | /* globals it expect */ 2 | 3 | import loader from "./componentLoader"; 4 | 5 | it("returns an object with keys when using .showcasefiles", () => { 6 | // mocks the showcase structure that is exported in times-components 7 | const mockShowcase = { 8 | default: { 9 | name: "Primitives/ArticleLabel", 10 | children: [ 11 | { 12 | type: "story", 13 | name: "small", 14 | component: () => "lol" 15 | } 16 | ] 17 | } 18 | }; 19 | 20 | const getShowcasesObject = () => [mockShowcase]; 21 | const loadedShowcases = loader(getShowcasesObject); 22 | const returnedComponent = loadedShowcases["primitives/articlelabel:small"](); 23 | expect(returnedComponent).toEqual("lol"); 24 | }); 25 | 26 | it("filters out non story showcases", () => { 27 | // mocks the showcase structure that is exported in times-components 28 | const mockShowcase = { 29 | default: { 30 | name: "Primitives/ArticleLabel", 31 | children: [ 32 | { 33 | type: "not a story", 34 | name: "small", 35 | component: () => "lol" 36 | } 37 | ] 38 | } 39 | }; 40 | 41 | const getShowcasesObject = () => [mockShowcase]; 42 | 43 | const loaded = loader(getShowcasesObject); 44 | expect(loaded).toEqual({}); 45 | }); 46 | 47 | it("filters out ignored story showcases", () => { 48 | // mocks the showcase structure that is exported in times-components 49 | const mockShowcase = { 50 | default: { 51 | name: "Primitives/ArticleLabel", 52 | children: [ 53 | { 54 | type: "story", 55 | hasExternalDeps: true, 56 | name: "small", 57 | component: () => "lol" 58 | }, 59 | { 60 | type: "story", 61 | name: "shown", 62 | component: () => "lol" 63 | } 64 | ] 65 | } 66 | }; 67 | 68 | const getShowcasesObject = () => [mockShowcase]; 69 | 70 | const loaded = loader(getShowcasesObject); 71 | expect(Object.keys(loaded)).toEqual(["primitives/articlelabel:shown"]); 72 | }); 73 | 74 | it("returns showcases without a platform", () => { 75 | const mockShowcase = { 76 | default: { 77 | name: "Primitives/ArticleLabel", 78 | children: [ 79 | { 80 | type: "story", 81 | name: "small", 82 | component: () => "lol" 83 | } 84 | ] 85 | } 86 | }; 87 | 88 | const getShowcasesObject = () => [mockShowcase]; 89 | const loadedShowcases = loader(getShowcasesObject); 90 | const returnedComponent = loadedShowcases["primitives/articlelabel:small"](); 91 | expect(returnedComponent).toEqual("lol"); 92 | }); 93 | 94 | it("filters out showcases that don't match specified plaform", () => { 95 | const mockShowcase = { 96 | default: { 97 | name: "Primitives/ArticleLabel", 98 | children: [ 99 | { 100 | platform: "native", 101 | type: "story", 102 | name: "small", 103 | component: () => "lol" 104 | } 105 | ] 106 | } 107 | }; 108 | 109 | const getShowcasesObject = () => [mockShowcase]; 110 | const loaded = loader(getShowcasesObject, "web"); 111 | expect(loaded).toEqual({}); 112 | }); 113 | 114 | it("does not explode when a showcase file has no default export", () => { 115 | let mockShowcase; 116 | 117 | const getShowcasesObject = () => [mockShowcase]; 118 | 119 | const loaded = loader(getShowcasesObject, "web"); 120 | expect(loaded).toEqual({}); 121 | }); 122 | -------------------------------------------------------------------------------- /ios/e2eTests.app/Frameworks/XCTest.framework/Headers/XCTestSuite.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2013-2015 Apple Inc. All rights reserved. 3 | // 4 | // Copyright (c) 1997-2005, Sen:te (Sente SA). All rights reserved. 5 | // 6 | // Use of this source code is governed by the following license: 7 | // 8 | // Redistribution and use in source and binary forms, with or without modification, 9 | // are permitted provided that the following conditions are met: 10 | // 11 | // (1) Redistributions of source code must retain the above copyright notice, 12 | // this list of conditions and the following disclaimer. 13 | // 14 | // (2) Redistributions in binary form must reproduce the above copyright notice, 15 | // this list of conditions and the following disclaimer in the documentation 16 | // and/or other materials provided with the distribution. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 19 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 | // IN NO EVENT SHALL Sente SA OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 23 | // OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 | // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 26 | // EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | // Note: this license is equivalent to the FreeBSD license. 29 | // 30 | // This notice may not be removed from this file. 31 | 32 | #import 33 | 34 | NS_ASSUME_NONNULL_BEGIN 35 | 36 | /*! 37 | * @class XCTestSuite 38 | * A concrete subclass of XCTest, XCTestSuite is a collection of test cases. Suites 39 | * are usually managed by the IDE, but XCTestSuite also provides API for dynamic test 40 | * and suite management: 41 | 42 | XCTestSuite *suite = [XCTestSuite testSuiteWithName:@"My tests"]; 43 | [suite addTest:[MathTest testCaseWithSelector:@selector(testAdd)]]; 44 | [suite addTest:[MathTest testCaseWithSelector:@selector(testDivideByZero)]]; 45 | 46 | * Alternatively, a test suite can extract the tests to be run automatically. To do so, 47 | * pass the class of your test case class to the suite's constructor: 48 | 49 | XCTestSuite *suite = [XCTestSuite testSuiteForTestCaseClass:[MathTest class]]; 50 | 51 | * This creates a suite with all the methods starting with "test" that take no arguments. 52 | * Also, a test suite of all the test cases found in the runtime can be created automatically: 53 | 54 | XCTestSuite *suite = [XCTestSuite defaultTestSuite]; 55 | 56 | * This creates a suite of suites with all the XCTestCase subclasses methods that start 57 | * with "test" and take no arguments. 58 | */ 59 | @interface XCTestSuite : XCTest { 60 | #ifndef __OBJC2__ 61 | @private 62 | id _internalImplementation; 63 | #endif 64 | } 65 | 66 | + (instancetype)defaultTestSuite; 67 | + (instancetype)testSuiteForBundlePath:(NSString *)bundlePath; 68 | + (instancetype)testSuiteForTestCaseWithName:(NSString *)name; 69 | + (instancetype)testSuiteForTestCaseClass:(Class)testCaseClass; 70 | 71 | + (instancetype)testSuiteWithName:(NSString *)name; 72 | - (instancetype)initWithName:(NSString *)name NS_DESIGNATED_INITIALIZER; 73 | 74 | - (void)addTest:(XCTest *)test; 75 | 76 | @property (readonly, copy) NSArray <__kindof XCTest *> *tests; 77 | 78 | @end 79 | 80 | NS_ASSUME_NONNULL_END 81 | 82 | -------------------------------------------------------------------------------- /ios/e2eTests/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 21 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /ios/e2eTests.app/Frameworks/XCTest.framework/Headers/XCAbstractTest.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2013-2015 Apple Inc. All rights reserved. 3 | // 4 | // Copyright (c) 1997-2005, Sen:te (Sente SA). All rights reserved. 5 | // 6 | // Use of this source code is governed by the following license: 7 | // 8 | // Redistribution and use in source and binary forms, with or without modification, 9 | // are permitted provided that the following conditions are met: 10 | // 11 | // (1) Redistributions of source code must retain the above copyright notice, 12 | // this list of conditions and the following disclaimer. 13 | // 14 | // (2) Redistributions in binary form must reproduce the above copyright notice, 15 | // this list of conditions and the following disclaimer in the documentation 16 | // and/or other materials provided with the distribution. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 19 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 | // IN NO EVENT SHALL Sente SA OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 23 | // OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 | // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 26 | // EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | // Note: this license is equivalent to the FreeBSD license. 29 | // 30 | // This notice may not be removed from this file. 31 | 32 | #import 33 | 34 | NS_ASSUME_NONNULL_BEGIN 35 | 36 | @class XCTestRun; 37 | 38 | /*! 39 | * @class XCTest 40 | * 41 | * An abstract base class for testing. XCTestCase and XCTestSuite extend XCTest to provide 42 | * for creating, managing, and executing tests. Most developers will not need to subclass 43 | * XCTest directly. 44 | */ 45 | @interface XCTest : NSObject { 46 | #ifndef __OBJC2__ 47 | @private 48 | id _internal; 49 | #endif 50 | } 51 | 52 | /*! 53 | * @property testCaseCount 54 | * Number of test cases. Must be overridden by subclasses. 55 | */ 56 | @property (readonly) NSUInteger testCaseCount; 57 | 58 | /*! 59 | * @property name 60 | * Test's name. Must be overridden by subclasses. 61 | */ 62 | @property (readonly, copy, nullable) NSString *name; 63 | 64 | /*! 65 | * @property testRunClass 66 | * The XCTestRun subclass that will be instantiated when the test is run to hold 67 | * the test's results. Must be overridden by subclasses. 68 | */ 69 | @property (readonly, nullable) Class testRunClass; 70 | 71 | /*! 72 | * @property testRun 73 | * The test run object that executed the test, an instance of testRunClass. If the test has not yet been run, this will be nil. 74 | */ 75 | @property (readonly, nullable) XCTestRun *testRun; 76 | 77 | /*! 78 | * @method -performTest: 79 | * The method through which tests are executed. Must be overridden by subclasses. 80 | */ 81 | - (void)performTest:(XCTestRun *)run; 82 | 83 | /*! 84 | * @method -runTest 85 | * Creates an instance of the testRunClass and passes it as a parameter to -performTest:. 86 | */ 87 | - (void)runTest; 88 | 89 | /*! 90 | * @method -setUp 91 | * Setup method called before the invocation of each test method in the class. 92 | */ 93 | - (void)setUp; 94 | 95 | /*! 96 | * @method -tearDown 97 | * Teardown method called after the invocation of each test method in the class. 98 | */ 99 | - (void)tearDown; 100 | 101 | @end 102 | 103 | NS_ASSUME_NONNULL_END 104 | -------------------------------------------------------------------------------- /ios/e2eTests.app/Frameworks/XCTest.framework/Headers/XCTKVOExpectation.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016 Apple Inc. All rights reserved. 3 | // 4 | 5 | #import 6 | #import 7 | #import 8 | 9 | NS_ASSUME_NONNULL_BEGIN 10 | 11 | /*! 12 | * @class XCTKVOExpectation 13 | * Expectation subclass for waiting on a condition defined Key Value Observation of a key path for an object. 14 | */ 15 | @interface XCTKVOExpectation : XCTestExpectation { 16 | #ifndef __OBJC2__ 17 | @private 18 | id _internal; 19 | #endif 20 | } 21 | 22 | - (instancetype)init NS_UNAVAILABLE; 23 | - (instancetype)initWithDescription:(NSString *)expectationDescription NS_UNAVAILABLE; 24 | 25 | /*! 26 | * @method -initWithKeyPath:object:expectedValue:options: 27 | * 28 | * @discussion 29 | * Initializes an expectation that is fulfilled when a key value coding compliant change is made such 30 | * that the specified key path of the observed object has the expected value. 31 | */ 32 | - (instancetype)initWithKeyPath:(NSString *)keyPath object:(id)object expectedValue:(nullable id)expectedValue options:(NSKeyValueObservingOptions)options NS_DESIGNATED_INITIALIZER; 33 | 34 | /*! 35 | * @method -initWithKeyPath:object:expectedValue: 36 | * 37 | * @discussion 38 | * Initializes an expectation that is fulfilled when a key value coding compliant change is made such 39 | * that the specified key path of the observed object has the expected value. The NSKeyValueObservingOptions 40 | * passed for this initializer include NSKeyValueObservingOptionInitial, so the object/key path will be 41 | * checked immediately. The options also include NSKeyValueObservingOptionNew and NSKeyValueObservingOptionOld, 42 | * so if a handler is used the change dictionary passed to it will contain NSKeyValueChangeNewKey and 43 | * NSKeyValueChangeOldKey entries. 44 | */ 45 | - (instancetype)initWithKeyPath:(NSString *)keyPath object:(id)object expectedValue:(nullable id)expectedValue; 46 | 47 | /*! 48 | * @method -initWithKeyPath:object: 49 | * 50 | * @discussion 51 | * Convenience initializer that is fulfilled by any change to the specified key path of the observed object. 52 | * The NSKeyValueObservingOptions passed for this initializer do not include NSKeyValueObservingOptionInitial 53 | * since there is no value to check. If that behavior is desired in conjunction with a handler, use the 54 | * designated initializer. The options do include NSKeyValueObservingOptionNew and NSKeyValueObservingOptionOld, 55 | * so if a handler is used the change dictionary passed to it will contain NSKeyValueChangeNewKey and 56 | * NSKeyValueChangeOldKey entries. 57 | */ 58 | - (instancetype)initWithKeyPath:(NSString *)keyPath object:(id)object; 59 | 60 | /*! 61 | * @property keyPath 62 | * Returns the key path that is being monitored for the KVO change. 63 | */ 64 | @property (readonly, copy) NSString *keyPath; 65 | 66 | /*! 67 | * @property observedObject 68 | * Returns the object that is being monitored for the KVO change. 69 | */ 70 | @property (readonly, strong) id observedObject; 71 | 72 | /*! 73 | * @property expectedValue 74 | * Returns the value that the expectation is waiting for the observed object/key path to have. 75 | */ 76 | @property (nullable, readonly, strong) id expectedValue; 77 | 78 | /*! 79 | * @property options 80 | * The KVO options used when the expectation registered for observation. 81 | */ 82 | @property (readonly) NSKeyValueObservingOptions options; 83 | 84 | /*! 85 | * @property handler 86 | * Allows the caller to install a special handler to do custom evaluation of the change to the value 87 | * of the object/key path. If a handler is set, expectedValue will be ignored. 88 | */ 89 | @property (nullable, copy) XCKeyValueObservingExpectationHandler handler; 90 | 91 | @end 92 | 93 | NS_ASSUME_NONNULL_END 94 | -------------------------------------------------------------------------------- /packages/app/src/components/navigation/navigation.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | import { StyleSheet, ScrollView, TouchableOpacity } from "react-native"; 3 | import io from "socket.io-client"; 4 | import { DrawerItems } from "react-navigation"; 5 | import NavigationHeader from "./navigationHeader"; 6 | import ParentNavigationItem from "./parentNavigationItem"; 7 | 8 | const config = { 9 | transports: ["websocket"], 10 | query: { 11 | clientType: "app" 12 | } 13 | }; 14 | 15 | const fructoseServerUrl = "http://localhost:7811"; 16 | 17 | const styles = StyleSheet.create({ 18 | isParentMenuTouch: { 19 | paddingLeft: 13, 20 | paddingTop: 15 21 | }, 22 | header: { 23 | color: "white", 24 | fontSize: 40, 25 | textAlign: "center" 26 | }, 27 | version: { 28 | padding: 10, 29 | color: "white", 30 | fontSize: 20, 31 | textAlign: "left" 32 | }, 33 | text: { 34 | paddingTop: 10, 35 | color: "white", 36 | fontSize: 16, 37 | textAlign: "center" 38 | } 39 | }); 40 | 41 | const getParentComponentNames = obj => [ 42 | ...new Set( 43 | obj.map(item => item.key.split("/")[0]).filter(parent => parent !== "Home") 44 | ) 45 | ]; 46 | 47 | class Navigation extends Component { 48 | constructor({ items, ...restProps }) { 49 | super(); 50 | this.socket = io(fructoseServerUrl, config); 51 | this.items = items; 52 | this.restProps = restProps; 53 | this.allComponentNames = this.items 54 | .map(component => component.key) 55 | .filter(component => component !== "Home"); 56 | this.parentComponentNames = getParentComponentNames(this.items); 57 | this.navigateToCallback = this.navigateToCallback.bind(this); 58 | 59 | this.state = { 60 | isParentMenu: true 61 | }; 62 | 63 | this.socket.on("load-component-in-app", componentToLoadInApp => { 64 | if (componentToLoadInApp) { 65 | this.restProps.navigation.navigate(componentToLoadInApp.toLowerCase()); 66 | } else { 67 | this.restProps.navigation.navigate("Home"); 68 | } 69 | }); 70 | 71 | this.socket.on("get-loaded-app-components", () => 72 | this.socket.emit("send-loaded-app-components", this.allComponentNames) 73 | ); 74 | } 75 | 76 | componentDidMount() { 77 | this.socket.emit("fructose-app-ready"); 78 | } 79 | 80 | componentDidUpdate() { 81 | this.socket.emit("component-loaded-in-app"); 82 | } 83 | 84 | navigateToCallback() { 85 | this.setState({ isParentMenu: true }); 86 | } 87 | 88 | renderParentItems(parentsToRender) { 89 | return parentsToRender.map(item => ( 90 | { 94 | this.setState({ 95 | isParentMenu: false, 96 | selectedParent: item 97 | }); 98 | }} 99 | /> 100 | )); 101 | } 102 | 103 | render() { 104 | if (this.state.isParentMenu) { 105 | return [ 106 | this.state.isParentMenu} 108 | navigateToCallback={this.navigateToCallback} 109 | key="header" 110 | />, 111 | 112 | 113 | {this.renderParentItems(this.parentComponentNames)} 114 | 115 | ]; 116 | } 117 | 118 | const childrenComponents = this.items.filter( 119 | item => item.key.split("/")[0] === this.state.selectedParent 120 | ); 121 | 122 | return [ 123 | this.state.isParentMenu} 126 | navigateToCallback={this.navigateToCallback} 127 | />, 128 | 129 | 134 | 135 | ]; 136 | } 137 | } 138 | 139 | export default Navigation; 140 | -------------------------------------------------------------------------------- /ios/e2eTests.app/Frameworks/XCTest.framework/Headers/XCUIElementQuery.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2015 Apple Inc. All rights reserved. 3 | // 4 | 5 | #import 6 | 7 | #if XCT_UI_TESTING_AVAILABLE 8 | 9 | #import 10 | #import 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | XCT_EXPORT NSString *XCUIIdentifierCloseWindow; 15 | XCT_EXPORT NSString *XCUIIdentifierMinimizeWindow; 16 | XCT_EXPORT NSString *XCUIIdentifierZoomWindow; 17 | XCT_EXPORT NSString *XCUIIdentifierFullScreenWindow; 18 | 19 | @class XCUIElement; 20 | 21 | /*! Object for locating elements that can be chained with other queries. */ 22 | NS_CLASS_AVAILABLE(10_11, 9_0) 23 | @interface XCUIElementQuery : NSObject 24 | 25 | /*! Returns an element that will use the query for resolution. */ 26 | @property (readonly) XCUIElement *element; 27 | 28 | /*! Evaluates the query at the time it is called and returns the number of matches found. */ 29 | @property (readonly) NSUInteger count; 30 | 31 | /*! Returns an element that will resolve to the index into the query's result set. */ 32 | - (XCUIElement *)elementAtIndex:(NSUInteger)index NS_DEPRECATED(10_11, 10_11, 9_0, 9_0, "Use elementBoundByIndex instead."); 33 | 34 | /*! Returns an element that will use the index into the query's results to determine which underlying accessibility element it is matched with. */ 35 | - (XCUIElement *)elementBoundByIndex:(NSUInteger)index; 36 | 37 | /*! Returns an element that matches the predicate. The predicate will be evaluated against objects of type id. */ 38 | - (XCUIElement *)elementMatchingPredicate:(NSPredicate *)predicate; 39 | 40 | /*! Returns an element that matches the type and identifier. */ 41 | - (XCUIElement *)elementMatchingType:(XCUIElementType)elementType identifier:(nullable NSString *)identifier; 42 | 43 | /*! Keyed subscripting is implemented as a shortcut for matching an identifier only. For example, app.descendants["Foo"] -> XCUIElement. */ 44 | - (XCUIElement *)objectForKeyedSubscript:(NSString *)key; 45 | 46 | /*! Immediately evaluates the query and returns an array of elements bound to the resulting accessibility elements. */ 47 | @property (readonly, copy) NSArray *allElementsBoundByAccessibilityElement; 48 | 49 | /*! Immediately evaluates the query and returns an array of elements bound by the index of each result. */ 50 | @property (readonly, copy) NSArray *allElementsBoundByIndex; 51 | 52 | /*! Returns a new query that finds the descendants of all the elements found by the receiver. */ 53 | - (XCUIElementQuery *)descendantsMatchingType:(XCUIElementType)type; 54 | 55 | /*! Returns a new query that finds the direct children of all the elements found by the receiver. */ 56 | - (XCUIElementQuery *)childrenMatchingType:(XCUIElementType)type; 57 | 58 | /*! Returns a new query that applies the specified attributes or predicate to the receiver. The predicate will be evaluated against objects of type id. */ 59 | - (XCUIElementQuery *)matchingPredicate:(NSPredicate *)predicate; 60 | - (XCUIElementQuery *)matchingType:(XCUIElementType)elementType identifier:(nullable NSString *)identifier; 61 | - (XCUIElementQuery *)matchingIdentifier:(NSString *)identifier; 62 | 63 | /*! Returns a new query for finding elements that contain a descendant matching the specification. The predicate will be evaluated against objects of type id. */ 64 | - (XCUIElementQuery *)containingPredicate:(NSPredicate *)predicate; 65 | - (XCUIElementQuery *)containingType:(XCUIElementType)elementType identifier:(nullable NSString *)identifier; 66 | 67 | /*! 68 | @discussion 69 | Provides debugging information about the query. The data in the string will vary based on the time 70 | at which it is captured, but it may include any of the following as well as additional data: 71 | • A description of each step of the query. 72 | • Information about the inputs and matched outputs of each step of the query. 73 | This data should be used for debugging only - depending on any of the data as part of a test is unsupported. 74 | */ 75 | @property (readonly, copy) NSString *debugDescription; 76 | 77 | @end 78 | 79 | NS_ASSUME_NONNULL_END 80 | 81 | #endif 82 | -------------------------------------------------------------------------------- /packages/test-helpers/src/bin/github-comment-manager.test.js: -------------------------------------------------------------------------------- 1 | /* global describe it expect */ 2 | import githubCommentManager from "./github-comment-manager"; 3 | 4 | const nock = require("nock"); 5 | 6 | const account = "testAccountName"; 7 | const token = "testKey"; 8 | const repository = "testRepo"; 9 | const pullRequest = 1; 10 | const documentPath = "index.html"; 11 | 12 | const noCommentsResponse = [ 13 | { 14 | id: 1, 15 | user: { 16 | login: "not test account name" 17 | } 18 | } 19 | ]; 20 | 21 | const mixedCommentsResponse = [ 22 | { 23 | id: 1, 24 | body: "If you use Expo, view our components by scanning this qr code:
", 25 | user: { 26 | login: "not test account name" 27 | } 28 | }, 29 | { 30 | id: 2, 31 | body: "If you use Expo, view our components by scanning this qr code:
", 32 | user: { 33 | login: account 34 | } 35 | }, 36 | { 37 | id: 3, 38 | body: "If you use Expo, view our components by scanning this qr code:
", 39 | user: { 40 | login: "a different non test account name" 41 | } 42 | } 43 | ]; 44 | 45 | const multipleUserCommentsResponse = [ 46 | { 47 | id: 1, 48 | body: "If you use Expo, view our components by scanning this qr code:
", 49 | user: { 50 | login: account 51 | } 52 | }, 53 | { 54 | id: 2, 55 | body: "If you use Expo, view our components by scanning this qr code:
", 56 | user: { 57 | login: account 58 | } 59 | } 60 | ]; 61 | 62 | const sameUserCommentsResponse = [ 63 | { 64 | id: 1, 65 | body: "Please find visual snapshots of your changed components here:", 66 | user: { 67 | login: account 68 | } 69 | }, 70 | { 71 | id: 2, 72 | body: "If you use Expo, view our components by scanning this qr code:
", 73 | user: { 74 | login: account 75 | } 76 | } 77 | ]; 78 | 79 | describe("deleteAllExpoComments", () => { 80 | it("should delete multiple Expo comments", async () => { 81 | nock("https://api.github.com") 82 | .get(`/repos/${account}/${repository}/issues/${pullRequest}/comments`) 83 | .reply(200, multipleUserCommentsResponse); 84 | 85 | nock("https://api.github.com") 86 | .delete(`/repos/${account}/${repository}/issues/comments/1`) 87 | .reply(200); 88 | nock("https://api.github.com") 89 | .delete(`/repos/${account}/${repository}/issues/comments/2`) 90 | .reply(200); 91 | 92 | const deletedCount = await githubCommentManager.deleteAllExpoComments( 93 | account, 94 | token, 95 | pullRequest, 96 | repository 97 | ); 98 | 99 | expect(deletedCount).toEqual(2); 100 | }); 101 | 102 | it("should only delete expo comments", async () => { 103 | nock("https://api.github.com") 104 | .get(`/repos/${account}/${repository}/issues/${pullRequest}/comments`) 105 | .reply(200, sameUserCommentsResponse); 106 | 107 | nock("https://api.github.com") 108 | .delete(`/repos/${account}/${repository}/issues/comments/2`) 109 | .reply(200); 110 | 111 | const deletedCount = await githubCommentManager.deleteAllExpoComments( 112 | account, 113 | token, 114 | pullRequest, 115 | repository 116 | ); 117 | 118 | expect(deletedCount).toEqual(1); 119 | }); 120 | }); 121 | 122 | describe("createNewExpoComment", () => { 123 | it("should create an expo comment", async () => { 124 | nock("https://api.github.com") 125 | .post( 126 | `/repos/${account}/${repository}/issues/${pullRequest}/comments`, 127 | `{"body": "If you use Expo, view our components by scanning this qr code:


This has been made possible through [Fructose](https://github.com/newsuk/fructose) "}` 128 | ) 129 | .reply(200); 130 | 131 | const successful = await githubCommentManager 132 | .createNewExpoComment( 133 | account, 134 | token, 135 | documentPath, 136 | pullRequest, 137 | repository 138 | ) 139 | .then(() => true) 140 | .catch(error => { 141 | console.log(error); 142 | return false; 143 | }); 144 | 145 | expect(successful).toEqual(true); 146 | }); 147 | }); 148 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@times-components/fructose", 3 | "version": "3.12.0", 4 | "main": "index.js", 5 | "scripts": { 6 | "test:unit": "jest ./packages --verbose --forceExit", 7 | "test": "./scripts/tests.sh", 8 | "e2e:start": "node node_modules/react-native/local-cli/cli.js start --config='./e2eTests/rn-cli.config.js' --resetCache", 9 | "e2e:test": "yarn test:ios && yarn test:android && yarn test:web", 10 | "e2e:web": "packages/web/bin/start.js --build-dir ./e2eTests/fructose", 11 | "e2e:test:web": "./e2eTests/scripts/web-tests.sh", 12 | "e2e:test:ios": "./e2eTests/scripts/ios-tests.sh", 13 | "e2e:test:android": "./e2eTests/scripts/android-tests.sh", 14 | "e2e:test:android-ci": "SAUCE_USERNAME=${SAUCE_USERNAME} SAUCE_KEY=${SAUCE_KEY} ./e2eTests/scripts/android-saucelabs-tests.sh", 15 | "precommit-msg": "echo 'Pre-commit checks...' && exit 0", 16 | "lint-staged": "lint-staged", 17 | "lint:packages": "eslint . --fix", 18 | "lint:fructose": "eslint e2eTests/fructose /--fix", 19 | "lint:e2eTests": "eslint e2eTests /--fix", 20 | "prettier:diff": "prettier --list-different '**/*.js'", 21 | "prettier:write": "prettier --write '**/*.js'", 22 | "prepare": "babel packages/test-helpers/src --out-dir packages/test-helpers/lib" 23 | }, 24 | "bin": { 25 | "fructose-web": "packages/web/bin/start.js", 26 | "fructose-tunnel": "packages/test-helpers/bin/createTunnel.js", 27 | "fructose": "packages/test-helpers/lib/bin/run.js" 28 | }, 29 | "pre-commit": [ 30 | "precommit-msg", 31 | "lint-staged" 32 | ], 33 | "lint-staged": { 34 | "**/*.js": [ 35 | "lint:packages", 36 | "lint:fructose", 37 | "lint:e2eTests", 38 | "prettier --write", 39 | "git add" 40 | ] 41 | }, 42 | "jest": { 43 | "preset": "react-native", 44 | "snapshotSerializers": [ 45 | "enzyme-to-json/serializer" 46 | ], 47 | "modulePathIgnorePatterns": [ 48 | "/packages/test-helpers/lib" 49 | ], 50 | "transformIgnorePatterns": [ 51 | "node_modules/(?!react-native|react-navigation|fructose-app|@times-components/image)" 52 | ] 53 | }, 54 | "dependencies": { 55 | "babel-polyfill": "^6.26.0", 56 | "callsite": "^1.0.0", 57 | "chromeless": "^1.3.0", 58 | "commander": "2.19.0", 59 | "express": "^4.16.2", 60 | "github-comment-manager": "^1.1.5", 61 | "html-webpack-plugin": "3.2.0", 62 | "ngrok": "^2.2.24", 63 | "npmlog": "^4.1.2", 64 | "prop-types": "^15.6.0", 65 | "react-native": "0.55.4", 66 | "react-native-side-menu": "^1.1.3", 67 | "react-navigation": "^2.17.0", 68 | "request": "^2.82.0", 69 | "server-destroy": "^1.0.1", 70 | "socket.io": "1.7.4", 71 | "socket.io-client": "1.7.4", 72 | "webpack": "4.6.0", 73 | "webpack-dev-server": "3.1.7", 74 | "webpack-merge": "^4.1.1" 75 | }, 76 | "peerDependencies": { 77 | "react": ">= 16.3.1", 78 | "react-native": "0.55.4" 79 | }, 80 | "devDependencies": { 81 | "babel-cli": "^6.26.0", 82 | "babel-core": "6.26.3", 83 | "babel-jest": "19.0.0", 84 | "babel-loader": "7.1.4", 85 | "babel-plugin-react-native-web": "^0.8.9", 86 | "babel-plugin-transform-regenerator": "^6.26.0", 87 | "babel-preset-react-native": "^4.0.0", 88 | "babel-register": "^6.26.0", 89 | "compression-webpack-plugin": "^1.0.0", 90 | "enzyme": "^3.2.0", 91 | "enzyme-adapter-react-16": "^1.1.0", 92 | "enzyme-to-json": "^3.2.2", 93 | "eslint": "4.18.0", 94 | "eslint-config-airbnb": "^16.1.0", 95 | "eslint-config-prettier": "^2.9.0", 96 | "eslint-plugin-import": "^2.8.0", 97 | "eslint-plugin-jsx-a11y": "^6.0.3", 98 | "eslint-plugin-react": "^7.6.1", 99 | "file-loader": "1.1.11", 100 | "http-serve": "^1.0.1", 101 | "jest": "23.3.0", 102 | "jest-environment-node-debug": "2.0.0", 103 | "lint-staged": "4.0.0", 104 | "nock": "^9.2.5", 105 | "portfinder": "^1.0.13", 106 | "pre-commit": "^1.2.2", 107 | "prettier": "^1.8.2", 108 | "react": "16.3.1", 109 | "react-art": "16.4.2", 110 | "react-dom": "16.4.2", 111 | "react-hot-loader": "^1.3.1", 112 | "react-native-showcase-loader": "1.0.1", 113 | "react-native-web": "0.8.9", 114 | "react-test-renderer": "16.3.1", 115 | "url-loader": "^0.5.8", 116 | "wd": "^1.4.1", 117 | "webpack-cli": "^3.1.0" 118 | }, 119 | "author": "News UK & Ireland Ltd", 120 | "license": "BSD-3-Clause", 121 | "bugs": { 122 | "url": "https://github.com/rjanjua/fructose/issues" 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /ios/e2eTests.app/Frameworks/XCTest.framework/Headers/XCTestObservation.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2014-2015 Apple Inc. All rights reserved. 3 | // 4 | 5 | #import 6 | 7 | NS_ASSUME_NONNULL_BEGIN 8 | 9 | @class XCTestSuite, XCTestCase; 10 | 11 | /*! 12 | * @protocol XCTestObservation 13 | * 14 | * Objects conforming to XCTestObservation can register to be notified of the progress of test runs. See XCTestObservationCenter 15 | * for details on registration. 16 | * 17 | * Progress events are delivered in the following sequence: 18 | * 19 | * -testBundleWillStart: // exactly once per test bundle 20 | * -testSuiteWillStart: // exactly once per test suite 21 | * -testCaseWillStart: // exactly once per test case 22 | * -testCase:didFailWithDescription:... // zero or more times per test case, any time between test case start and finish 23 | * -testCaseDidFinish: // exactly once per test case 24 | * -testSuite:didFailWithDescription:... // zero or more times per test suite, any time between test suite start and finish 25 | * -testSuiteDidFinish: // exactly once per test suite 26 | * -testBundleDidFinish: // exactly once per test bundle 27 | */ 28 | @protocol XCTestObservation 29 | @optional 30 | 31 | /*! 32 | * @method -testBundleWillStart: 33 | * 34 | * Sent immediately before tests begin as a hook for any pre-testing setup. 35 | * 36 | * @param testBundle The bundle containing the tests that were executed. 37 | */ 38 | - (void)testBundleWillStart:(NSBundle *)testBundle; 39 | 40 | /*! 41 | * @method -testBundleDidFinish: 42 | * 43 | * Sent immediately after all tests have finished as a hook for any post-testing activity. The test process will generally 44 | * exit after this method returns, so if there is long running and/or asynchronous work to be done after testing, be sure 45 | * to implement this method in a way that it blocks until all such activity is complete. 46 | * 47 | * @param testBundle The bundle containing the tests that were executed. 48 | */ 49 | - (void)testBundleDidFinish:(NSBundle *)testBundle; 50 | 51 | /*! 52 | * @method -testSuiteWillStart: 53 | * 54 | * Sent when a test suite starts executing. 55 | * 56 | * @param testSuite The test suite that started. Additional information can be retrieved from the associated XCTestRun. 57 | */ 58 | - (void)testSuiteWillStart:(XCTestSuite *)testSuite; 59 | 60 | /*! 61 | * @method -testSuiteDidFail:withDescription:inFile:atLine: 62 | * 63 | * Sent when a test suite reports a failure. Suite failures are most commonly reported during suite-level setup and teardown 64 | * whereas failures during tests are reported for the test case alone and are not reported as suite failures. 65 | * 66 | * @param testSuite The test suite that failed. Additional information can be retrieved from the associated XCTestRun. 67 | * @param description A textual description of the failure. 68 | * @param filePath The path of file where the failure occurred, nil if unknown. 69 | * @param lineNumber The line where the failure was reported. 70 | */ 71 | - (void)testSuite:(XCTestSuite *)testSuite didFailWithDescription:(NSString *)description inFile:(nullable NSString *)filePath atLine:(NSUInteger)lineNumber; 72 | 73 | /*! 74 | * @method -testSuiteDidFinish: 75 | * 76 | * Sent when a test suite finishes executing. 77 | * 78 | * @param testSuite The test suite that finished. Additional information can be retrieved from the associated XCTestRun. 79 | */ 80 | - (void)testSuiteDidFinish:(XCTestSuite *)testSuite; 81 | 82 | /*! 83 | * @method -testCaseWillStart: 84 | * 85 | * Sent when a test case starts executing. 86 | * 87 | * @param testCase The test case that started. Additional information can be retrieved from the associated XCTestRun. 88 | */ 89 | - (void)testCaseWillStart:(XCTestCase *)testCase; 90 | 91 | /*! 92 | * @method -testCaseDidFail:withDescription:inFile:atLine: 93 | * 94 | * Sent when a test case reports a failure. 95 | * 96 | * @param testCase The test case that failed. Additional information can be retrieved from the associated XCTestRun. 97 | * @param description A textual description of the failure. 98 | * @param filePath The path of file where the failure occurred, nil if unknown. 99 | * @param lineNumber The line where the failure was reported. 100 | */ 101 | - (void)testCase:(XCTestCase *)testCase didFailWithDescription:(NSString *)description inFile:(nullable NSString *)filePath atLine:(NSUInteger)lineNumber; 102 | 103 | /*! 104 | * @method -testCaseDidFinish: 105 | * 106 | * Sent when a test case finishes executing. 107 | * 108 | * @param testCase The test case that finished. Additional information can be retrieved from the associated XCTestRun. 109 | */ 110 | - (void)testCaseDidFinish:(XCTestCase *)testCase; 111 | 112 | @end 113 | 114 | NS_ASSUME_NONNULL_END 115 | -------------------------------------------------------------------------------- /ios/e2eTests.app/Frameworks/XCTest.framework/Headers/XCUIElementTypeQueryProvider.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2015 Apple Inc. All rights reserved. 3 | // 4 | 5 | #import 6 | 7 | #if XCT_UI_TESTING_AVAILABLE 8 | 9 | NS_ASSUME_NONNULL_BEGIN 10 | 11 | @class XCUIElementQuery; 12 | 13 | @protocol XCUIElementTypeQueryProvider 14 | 15 | @property (readonly, copy) XCUIElementQuery *touchBars; 16 | @property (readonly, copy) XCUIElementQuery *groups; 17 | @property (readonly, copy) XCUIElementQuery *windows; 18 | @property (readonly, copy) XCUIElementQuery *sheets; 19 | @property (readonly, copy) XCUIElementQuery *drawers; 20 | @property (readonly, copy) XCUIElementQuery *alerts; 21 | @property (readonly, copy) XCUIElementQuery *dialogs; 22 | @property (readonly, copy) XCUIElementQuery *buttons; 23 | @property (readonly, copy) XCUIElementQuery *radioButtons; 24 | @property (readonly, copy) XCUIElementQuery *radioGroups; 25 | @property (readonly, copy) XCUIElementQuery *checkBoxes; 26 | @property (readonly, copy) XCUIElementQuery *disclosureTriangles; 27 | @property (readonly, copy) XCUIElementQuery *popUpButtons; 28 | @property (readonly, copy) XCUIElementQuery *comboBoxes; 29 | @property (readonly, copy) XCUIElementQuery *menuButtons; 30 | @property (readonly, copy) XCUIElementQuery *toolbarButtons; 31 | @property (readonly, copy) XCUIElementQuery *popovers; 32 | @property (readonly, copy) XCUIElementQuery *keyboards; 33 | @property (readonly, copy) XCUIElementQuery *keys; 34 | @property (readonly, copy) XCUIElementQuery *navigationBars; 35 | @property (readonly, copy) XCUIElementQuery *tabBars; 36 | @property (readonly, copy) XCUIElementQuery *tabGroups; 37 | @property (readonly, copy) XCUIElementQuery *toolbars; 38 | @property (readonly, copy) XCUIElementQuery *statusBars; 39 | @property (readonly, copy) XCUIElementQuery *tables; 40 | @property (readonly, copy) XCUIElementQuery *tableRows; 41 | @property (readonly, copy) XCUIElementQuery *tableColumns; 42 | @property (readonly, copy) XCUIElementQuery *outlines; 43 | @property (readonly, copy) XCUIElementQuery *outlineRows; 44 | @property (readonly, copy) XCUIElementQuery *browsers; 45 | @property (readonly, copy) XCUIElementQuery *collectionViews; 46 | @property (readonly, copy) XCUIElementQuery *sliders; 47 | @property (readonly, copy) XCUIElementQuery *pageIndicators; 48 | @property (readonly, copy) XCUIElementQuery *progressIndicators; 49 | @property (readonly, copy) XCUIElementQuery *activityIndicators; 50 | @property (readonly, copy) XCUIElementQuery *segmentedControls; 51 | @property (readonly, copy) XCUIElementQuery *pickers; 52 | @property (readonly, copy) XCUIElementQuery *pickerWheels; 53 | @property (readonly, copy) XCUIElementQuery *switches; 54 | @property (readonly, copy) XCUIElementQuery *toggles; 55 | @property (readonly, copy) XCUIElementQuery *links; 56 | @property (readonly, copy) XCUIElementQuery *images; 57 | @property (readonly, copy) XCUIElementQuery *icons; 58 | @property (readonly, copy) XCUIElementQuery *searchFields; 59 | @property (readonly, copy) XCUIElementQuery *scrollViews; 60 | @property (readonly, copy) XCUIElementQuery *scrollBars; 61 | @property (readonly, copy) XCUIElementQuery *staticTexts; 62 | @property (readonly, copy) XCUIElementQuery *textFields; 63 | @property (readonly, copy) XCUIElementQuery *secureTextFields; 64 | @property (readonly, copy) XCUIElementQuery *datePickers; 65 | @property (readonly, copy) XCUIElementQuery *textViews; 66 | @property (readonly, copy) XCUIElementQuery *menus; 67 | @property (readonly, copy) XCUIElementQuery *menuItems; 68 | @property (readonly, copy) XCUIElementQuery *menuBars; 69 | @property (readonly, copy) XCUIElementQuery *menuBarItems; 70 | @property (readonly, copy) XCUIElementQuery *maps; 71 | @property (readonly, copy) XCUIElementQuery *webViews; 72 | @property (readonly, copy) XCUIElementQuery *steppers; 73 | @property (readonly, copy) XCUIElementQuery *incrementArrows; 74 | @property (readonly, copy) XCUIElementQuery *decrementArrows; 75 | @property (readonly, copy) XCUIElementQuery *tabs; 76 | @property (readonly, copy) XCUIElementQuery *timelines; 77 | @property (readonly, copy) XCUIElementQuery *ratingIndicators; 78 | @property (readonly, copy) XCUIElementQuery *valueIndicators; 79 | @property (readonly, copy) XCUIElementQuery *splitGroups; 80 | @property (readonly, copy) XCUIElementQuery *splitters; 81 | @property (readonly, copy) XCUIElementQuery *relevanceIndicators; 82 | @property (readonly, copy) XCUIElementQuery *colorWells; 83 | @property (readonly, copy) XCUIElementQuery *helpTags; 84 | @property (readonly, copy) XCUIElementQuery *mattes; 85 | @property (readonly, copy) XCUIElementQuery *dockItems; 86 | @property (readonly, copy) XCUIElementQuery *rulers; 87 | @property (readonly, copy) XCUIElementQuery *rulerMarkers; 88 | @property (readonly, copy) XCUIElementQuery *grids; 89 | @property (readonly, copy) XCUIElementQuery *levelIndicators; 90 | @property (readonly, copy) XCUIElementQuery *cells; 91 | @property (readonly, copy) XCUIElementQuery *layoutAreas; 92 | @property (readonly, copy) XCUIElementQuery *layoutItems; 93 | @property (readonly, copy) XCUIElementQuery *handles; 94 | @property (readonly, copy) XCUIElementQuery *otherElements; 95 | 96 | @end 97 | 98 | NS_ASSUME_NONNULL_END 99 | 100 | #endif 101 | -------------------------------------------------------------------------------- /ios/e2eTests.xcodeproj/xcshareddata/xcschemes/e2eTests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 43 | 49 | 50 | 51 | 52 | 53 | 58 | 59 | 61 | 67 | 68 | 69 | 70 | 71 | 77 | 78 | 79 | 80 | 81 | 82 | 92 | 94 | 100 | 101 | 102 | 103 | 104 | 105 | 111 | 113 | 119 | 120 | 121 | 122 | 124 | 125 | 128 | 129 | 130 | --------------------------------------------------------------------------------