From 30b3bb3bd881d2a1210ed129e3c9280eff5c7acd Mon Sep 17 00:00:00 2001 From: Henning Hall Date: Wed, 5 Feb 2020 13:36:36 +0100 Subject: [PATCH] Add android tests --- .github/workflows/android.yml | 61 + .watchmanconfig | 1 + README.md | 11 +- android/build.gradle | 4 +- .../date_picker/DatePickerManager.java | 22 +- .../henninghall/date_picker/PickerView.java | 14 +- .../com/henninghall/date_picker/Style.java | 2 - .../henninghall/date_picker/WheelOrder.java | 4 +- .../src/main/res/layout/datepicker_view.xml | 7 + examples/detox/android/app/build.gradle | 4 +- examples/detox/android/build.gradle | 3 + examples/detox/android/settings.gradle | 2 +- examples/detox/e2e/init.js | 6 +- examples/detox/e2e/mocha.opts | 2 +- .../e2e/tests/24h-mode/hourWheel.spec.js | 28 + .../detox/e2e/tests/24h-mode/mode.spec.js | 49 + examples/detox/e2e/tests/maximumDate.spec.js | 131 + examples/detox/e2e/tests/minimumDate.spec.js | 134 + .../detox/e2e/tests/minuteInterval.spec.js | 34 + examples/detox/e2e/tests/mode.spec.js | 49 + examples/detox/e2e/tests/scrollAround.spec.js | 45 + examples/detox/e2e/tests/wheelOrder.spec.js | 95 + examples/detox/e2e/utils.js | 39 + examples/detox/index.android.js | 2 +- examples/detox/index.js | 2 +- .../ios/example.xcodeproj/project.pbxproj | 48 +- examples/detox/metro.config.js | 29 + examples/detox/package.json | 54 +- examples/detox/src/App.js | 84 + examples/detox/src/CustomPropValue.js | 49 + examples/detox/src/PropButton.js | 6 + examples/detox/src/PropSlider.js | 64 + examples/detox/src/exampleKeys.js | 6 + examples/detox/src/examples.js | 25 + examples/detox/src/examples/Advanced.js | 225 + examples/detox/src/examples/DateMode.js | 14 + examples/detox/src/examples/Minimal.js | 13 + examples/detox/src/examples/TimeMode.js | 14 + examples/detox/src/locales.js | 212 + examples/detox/src/propPickers/DateChange.js | 45 + examples/detox/src/propPickers/FadeToColor.js | 8 + .../detox/src/propPickers/LocalePicker.js | 39 + .../detox/src/propPickers/MinMaxDateChange.js | 55 + .../detox/src/propPickers/MinuteInterval.js | 18 + examples/detox/src/propPickers/ModePicker.js | 18 + examples/detox/src/propPickers/Scroll.js | 40 + examples/detox/src/propPickers/TextColor.js | 8 + .../propPickers/TimeZoneOffsetInMinutes.js | 20 + examples/detox/yarn.lock | 355 +- package-lock.json | 5785 +++++++++++++++++ package.json | 2 +- yarn.lock | 4448 +++++++++++++ 52 files changed, 12340 insertions(+), 95 deletions(-) create mode 100644 .github/workflows/android.yml create mode 100644 .watchmanconfig create mode 100644 examples/detox/e2e/tests/24h-mode/hourWheel.spec.js create mode 100644 examples/detox/e2e/tests/24h-mode/mode.spec.js create mode 100644 examples/detox/e2e/tests/maximumDate.spec.js create mode 100644 examples/detox/e2e/tests/minimumDate.spec.js create mode 100644 examples/detox/e2e/tests/minuteInterval.spec.js create mode 100644 examples/detox/e2e/tests/mode.spec.js create mode 100644 examples/detox/e2e/tests/scrollAround.spec.js create mode 100644 examples/detox/e2e/tests/wheelOrder.spec.js create mode 100644 examples/detox/e2e/utils.js create mode 100644 examples/detox/metro.config.js create mode 100644 examples/detox/src/App.js create mode 100644 examples/detox/src/CustomPropValue.js create mode 100644 examples/detox/src/PropButton.js create mode 100644 examples/detox/src/PropSlider.js create mode 100644 examples/detox/src/exampleKeys.js create mode 100644 examples/detox/src/examples.js create mode 100644 examples/detox/src/examples/Advanced.js create mode 100644 examples/detox/src/examples/DateMode.js create mode 100644 examples/detox/src/examples/Minimal.js create mode 100644 examples/detox/src/examples/TimeMode.js create mode 100644 examples/detox/src/locales.js create mode 100644 examples/detox/src/propPickers/DateChange.js create mode 100644 examples/detox/src/propPickers/FadeToColor.js create mode 100644 examples/detox/src/propPickers/LocalePicker.js create mode 100644 examples/detox/src/propPickers/MinMaxDateChange.js create mode 100644 examples/detox/src/propPickers/MinuteInterval.js create mode 100644 examples/detox/src/propPickers/ModePicker.js create mode 100644 examples/detox/src/propPickers/Scroll.js create mode 100644 examples/detox/src/propPickers/TextColor.js create mode 100644 examples/detox/src/propPickers/TimeZoneOffsetInMinutes.js create mode 100644 package-lock.json diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml new file mode 100644 index 0000000..697cfe8 --- /dev/null +++ b/.github/workflows/android.yml @@ -0,0 +1,61 @@ +name: "Android: build & test" + +on: [push, pull_request] + +jobs: + build_and_test: + name: Build & test + runs-on: macos-latest + timeout-minutes: 30 + + steps: + - name: Checkout + uses: actions/checkout@v1 + with: + fetch-depth: 1 + + - name: Node + uses: actions/setup-node@v1 + + - name: Use specific Java version for sdkmanager to work + uses: joschi/setup-jdk@v1 + with: + java-version: 'openjdk8' + architecture: 'x64' + + - name: Download Android Emulator Image + run: | + echo "y" | $ANDROID_HOME/tools/bin/sdkmanager --install "system-images;android-29;google_apis;x86" + echo "no" | $ANDROID_HOME/tools/bin/avdmanager create avd --force --name emu --device "Nexus 5X" -k 'system-images;android-29;google_apis;x86' + $ANDROID_HOME/emulator/emulator -list-avds + + - name: Install npm dependencies + working-directory: ./examples/detox + run: | + yarn install --frozen-lockfile + + - name: Build + working-directory: ./examples/detox + run: | + yarn build:android-ci + + - name: Start android emulator + working-directory: ./examples/detox + continue-on-error: true + run: | + echo "Starting emulator" + nohup $ANDROID_HOME/emulator/emulator -avd emu -no-audio -no-snapshot -no-window & + $ANDROID_HOME/platform-tools/adb wait-for-device shell 'while [[ -z $(getprop sys.boot_completed | tr -d '\r') ]]; do sleep 1; done; input keyevent 82' + $ANDROID_HOME/platform-tools/adb devices + echo "Emulator started" + + - name: Run tests + working-directory: ./examples/detox + run: yarn start & yarn test:android-ci + + - name: Upload artifacts + uses: actions/upload-artifact@v1 + if: failure() + with: + name: Failing tests + path: ./examples/detox/artifacts diff --git a/.watchmanconfig b/.watchmanconfig new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/.watchmanconfig @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/README.md b/README.md index 7aa4ac4..1c51332 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,5 @@ -# React Native Date Picker [![npm](https://img.shields.io/npm/v/react-native-date-picker.svg)](https://www.npmjs.com/package/react-native-date-picker) [![npm](https://img.shields.io/npm/dm/react-native-date-picker.svg)](https://www.npmjs.com/package/react-native-date-picker) +# React Native Date Picker [![npm](https://img.shields.io/npm/v/react-native-date-picker.svg)](https://www.npmjs.com/package/react-native-date-picker) [![Build status](https://img.shields.io/github/workflow/status/henninghall/react-native-date-picker/Android:%20build%20&%20test?label=tests)](https://github.com/henninghall/react-native-date-picker/actions) [![npm](https://img.shields.io/npm/dm/react-native-date-picker.svg)](https://www.npmjs.com/package/react-native-date-picker) - This is a React Native Date Picker with following main features: @@ -13,10 +8,6 @@ This is a React Native Date Picker with following main features: 🌍 Multiple languages
🎨 Customizable
- - diff --git a/android/build.gradle b/android/build.gradle index abe1003..26e7f33 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -25,7 +25,7 @@ android { dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') implementation 'com.facebook.react:react-native:+' - implementation 'com.henninghall.android:NumberPickerView:1.1.1' - implementation 'org.apache.commons:commons-lang3:3.6' + implementation 'com.henninghall.android:NumberPickerView:1.1.2' + implementation 'org.apache.commons:commons-lang3:3.7' implementation group: 'net.time4j', name: 'time4j-android', version: '4.2-2018i' } diff --git a/android/src/main/java/com/henninghall/date_picker/DatePickerManager.java b/android/src/main/java/com/henninghall/date_picker/DatePickerManager.java index ece4bcd..f15bd7f 100644 --- a/android/src/main/java/com/henninghall/date_picker/DatePickerManager.java +++ b/android/src/main/java/com/henninghall/date_picker/DatePickerManager.java @@ -1,9 +1,6 @@ package com.henninghall.date_picker; -import android.content.res.Resources; -import android.util.Log; -import android.util.TypedValue; - +import com.facebook.react.bridge.ReadableArray; import com.facebook.react.common.MapBuilder; import com.facebook.react.uimanager.SimpleViewManager; import com.facebook.react.uimanager.ThemedReactContext; @@ -19,6 +16,8 @@ import java.util.TimeZone; public class DatePickerManager extends SimpleViewManager { public static final String REACT_CLASS = "DatePickerManager"; + private static final int SCROLL = 1; + public static ThemedReactContext context; private String date; @@ -92,6 +91,21 @@ public class DatePickerManager extends SimpleViewManager { if(index == 0) view.style.setHeight(style); } + @Override + public Map getCommandsMap() { + return MapBuilder.of( + "scroll", SCROLL + ); + } + + public void receiveCommand(final PickerView view, int command, final ReadableArray args) { + if (command == SCROLL) { + int wheelIndex = args.getInt(0); + int scrollTimes = args.getInt(1); + view.scroll(wheelIndex, scrollTimes); + } + } + @Override protected void onAfterUpdateTransaction(PickerView view) { super.onAfterUpdateTransaction(view); diff --git a/android/src/main/java/com/henninghall/date_picker/PickerView.java b/android/src/main/java/com/henninghall/date_picker/PickerView.java index 32b9e20..7321e3d 100644 --- a/android/src/main/java/com/henninghall/date_picker/PickerView.java +++ b/android/src/main/java/com/henninghall/date_picker/PickerView.java @@ -23,7 +23,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Collection; -import java.util.Date; import java.util.List; import java.util.Locale; import java.util.TimeZone; @@ -130,7 +129,7 @@ public class PickerView extends RelativeLayout { } // Rounding cal to closest minute interval - public Calendar getInitialDate() { + public Calendar getInitialDate() { Calendar cal = Calendar.getInstance(); if(minuteInterval <= 1) return cal; int exactMinute = Integer.valueOf(minutesWheel.format.format(cal.getTime())); @@ -232,4 +231,15 @@ public class PickerView extends RelativeLayout { return new SimpleDateFormat(getFormatPattern(), locale); } + public void scroll(int wheelIndex, int scrollTimes) { + NumberPickerView picker = wheelOrder.getVisibleWheel(wheelIndex).picker; + int currentIndex = picker.getValue(); + int maxValue = picker.getMaxValue(); + boolean isWrapping = picker.getWrapSelectorWheel(); + int nextValue = currentIndex + scrollTimes; + if(nextValue <= maxValue || isWrapping) { + picker.smoothScrollToValue(nextValue % (maxValue + 1)); + } + + } } diff --git a/android/src/main/java/com/henninghall/date_picker/Style.java b/android/src/main/java/com/henninghall/date_picker/Style.java index 7d3a02f..89a9000 100644 --- a/android/src/main/java/com/henninghall/date_picker/Style.java +++ b/android/src/main/java/com/henninghall/date_picker/Style.java @@ -2,8 +2,6 @@ package com.henninghall.date_picker; import android.graphics.Color; import android.graphics.drawable.GradientDrawable; -import android.view.View; -import android.view.ViewGroup; import android.widget.ImageView; import com.henninghall.date_picker.wheelFunctions.SetShowCount; import com.henninghall.date_picker.wheelFunctions.TextColor; diff --git a/android/src/main/java/com/henninghall/date_picker/WheelOrder.java b/android/src/main/java/com/henninghall/date_picker/WheelOrder.java index 29de3e1..fdf24a2 100644 --- a/android/src/main/java/com/henninghall/date_picker/WheelOrder.java +++ b/android/src/main/java/com/henninghall/date_picker/WheelOrder.java @@ -27,7 +27,7 @@ public class WheelOrder }}; } - private void updateValueWheels(final Locale locale) { + private void updateAllWheels(final Locale locale) { try { this.orderedWheels = getOrderedWheels(locale); pickerView.wheelsWrapper.removeAllViews(); @@ -45,7 +45,7 @@ public class WheelOrder void update(final Locale locale) { - updateValueWheels(locale); + updateAllWheels(locale); pickerView.emptyWheelUpdater.update(); } diff --git a/android/src/main/res/layout/datepicker_view.xml b/android/src/main/res/layout/datepicker_view.xml index 0d088d8..558068b 100644 --- a/android/src/main/res/layout/datepicker_view.xml +++ b/android/src/main/res/layout/datepicker_view.xml @@ -29,6 +29,7 @@ /> { await detox.init(config) }) -beforeEach(async function() { +beforeEach(async function () { + await reset() await adapter.beforeEach(this) }) -afterEach(async function() { +afterEach(async function () { await adapter.afterEach(this) }) diff --git a/examples/detox/e2e/mocha.opts b/examples/detox/e2e/mocha.opts index d75a815..32c9522 100644 --- a/examples/detox/e2e/mocha.opts +++ b/examples/detox/e2e/mocha.opts @@ -1,4 +1,4 @@ --recursive --timeout 300000 ---bail --file e2e/init.js +--slow 30000 diff --git a/examples/detox/e2e/tests/24h-mode/hourWheel.spec.js b/examples/detox/e2e/tests/24h-mode/hourWheel.spec.js new file mode 100644 index 0000000..e1a86c0 --- /dev/null +++ b/examples/detox/e2e/tests/24h-mode/hourWheel.spec.js @@ -0,0 +1,28 @@ +const { scrollWheel, expectDate } = require("../../utils") + + +describe('Hour wheel', () => { + + before(async () => { + await device.reloadReactNative() + await element(by.text('Advanced')).tap() + }) + + it('should have 24 hours', async () => { + await scroll3HoursAndExpect("2000-01-01 03:00:00") + await scroll3HoursAndExpect("2000-01-01 06:00:00") + await scroll3HoursAndExpect("2000-01-01 09:00:00") + await scroll3HoursAndExpect("2000-01-01 12:00:00") + await scroll3HoursAndExpect("2000-01-01 15:00:00") + await scroll3HoursAndExpect("2000-01-01 18:00:00") + await scroll3HoursAndExpect("2000-01-01 21:00:00") + await scroll3HoursAndExpect("2000-01-01 00:00:00") + }) + + const scroll3HoursAndExpect = async (date) => { + await scrollWheel(1, 3) + await expectDate(date) + } + +}) + diff --git a/examples/detox/e2e/tests/24h-mode/mode.spec.js b/examples/detox/e2e/tests/24h-mode/mode.spec.js new file mode 100644 index 0000000..d22241d --- /dev/null +++ b/examples/detox/e2e/tests/24h-mode/mode.spec.js @@ -0,0 +1,49 @@ +const { setMode } = require("../../utils") + +describe('Modes - 24h', () => { + + before(async () => { + await device.reloadReactNative() + await element(by.text('Advanced')).tap() + }) + + it('datetime', async () => { + await setMode("datetime") + + await expect(element(by.id('day'))).toBeVisible() + await expect(element(by.id('minutes'))).toBeVisible() + await expect(element(by.id('hour'))).toBeVisible() + + await expect(element(by.id('ampm'))).toNotExist() + await expect(element(by.id('month'))).toNotExist() + await expect(element(by.id('date'))).toNotExist() + await expect(element(by.id('year'))).toNotExist() + }) + + it('date', async () => { + await setMode("date") + + await expect(element(by.id('month'))).toBeVisible() + await expect(element(by.id('date'))).toBeVisible() + await expect(element(by.id('year'))).toBeVisible() + + await expect(element(by.id('day'))).toNotExist() + await expect(element(by.id('minutes'))).toNotExist() + await expect(element(by.id('hour'))).toNotExist() + await expect(element(by.id('ampm'))).toNotExist() + }) + + it('time', async () => { + await setMode("time") + + await expect(element(by.id('minutes'))).toBeVisible() + await expect(element(by.id('hour'))).toBeVisible() + + await expect(element(by.id('ampm'))).toNotExist() + await expect(element(by.id('day'))).toNotExist() + await expect(element(by.id('month'))).toNotExist() + await expect(element(by.id('date'))).toNotExist() + await expect(element(by.id('year'))).toNotExist() + }) + +}) diff --git a/examples/detox/e2e/tests/maximumDate.spec.js b/examples/detox/e2e/tests/maximumDate.spec.js new file mode 100644 index 0000000..b307d0d --- /dev/null +++ b/examples/detox/e2e/tests/maximumDate.spec.js @@ -0,0 +1,131 @@ +const { scrollWheel, expectDate, setMaximumDate, setMode } = require("../utils") + +const initialDate = new Date(2000, 0, 1, 0, 0); +const secondOfJanuary = new Date(2000, 0, 2, 0, 0); +const secondOfJanuary2001 = new Date(2001, 0, 2, 0, 0); + +describe('Maximum date', () => { + + before(async () => { + await device.reloadReactNative() + await element(by.text('Advanced')).tap() + }) + + describe('cannot pass max date - datetime mode', () => { + + before(async () => { + await setMode("datetime") + await setMaximumDate(initialDate) + }) + + it('day wheel', async () => { + await scrollWheel(0, 2) + await expectDate("2000-01-01 00:00:00") + }) + + it('hour wheel', async () => { + await scrollWheel(1, 1) + await expectDate("2000-01-01 00:00:00") + }) + + it('minute wheel', async () => { + await scrollWheel(2, 1) + await expectDate("2000-01-01 00:00:00") + }) + + }) + + describe('cannot pass max date - date mode', () => { + + before(async () => { + await setMode("date") + await setMaximumDate(initialDate) + }) + + it('month wheel', async () => { + await scrollWheel(0, 1) + await expectDate("2000-01-01 00:00:00") + }) + + it('date wheel', async () => { + await scrollWheel(1, 1) + await expectDate("2000-01-01 00:00:00") + }) + + it('year wheel', async () => { + await scrollWheel(2, 1) + await expectDate("2000-01-01 00:00:00") + }) + + }) + + + describe('overshooting max date', () => { + + before(async () => { + await setMaximumDate(secondOfJanuary) + }) + + it('day wheel should not be possible to overshoot since it is not wrapping (no invalid dates exists)', async () => { + await setMode("datetime") + await scrollWheel(0, 1) + await expectDate("2000-01-02 00:00:00") + await scrollWheel(0, 1) + await expectDate("2000-01-02 00:00:00") + }) + + describe('date mode', () => { + + before(async () => { + await setMode("date") + await setMaximumDate(secondOfJanuary) + }) + + it('overshooting month wheel should set all other wheels to maximum possible date', async () => { + await scrollWheel(0, 1) + await expectDate("2000-01-02 00:00:00") + }) + + it('overshooting date wheel should reverse to highest possible date', async () => { + await scrollWheel(1, 5) + await expectDate("2000-01-02 00:00:00") + }) + + it('overshooting year wheel should set all other wheels to maximum possible date', async () => { + await setMaximumDate(secondOfJanuary2001) + await scrollWheel(0, 1) // set month to feb + await scrollWheel(2, 1) + await expectDate("2001-01-02 00:00:00") + }) + + }) + + describe('time mode', () => { + + before(async () => { + await setMode("time") + await setMaximumDate(initialDate) + }) + + it('overshooting hour wheel should reverse to highest possible time', async () => { + await scrollWheel(0, 5) + await expectDate("2000-01-01 00:00:00") + }) + + it('overshooting minute wheel should reverse to highest possible time', async () => { + await scrollWheel(1, 5) + await expectDate("2000-01-01 00:00:00") + }) + + it('overshooting am/pm wheel should reverse to highest possible time', async () => { + await scrollWheel(2, 1) + await expectDate("2000-01-01 00:00:00") + }) + + }) + + + + }) + +}) \ No newline at end of file diff --git a/examples/detox/e2e/tests/minimumDate.spec.js b/examples/detox/e2e/tests/minimumDate.spec.js new file mode 100644 index 0000000..d70f4b5 --- /dev/null +++ b/examples/detox/e2e/tests/minimumDate.spec.js @@ -0,0 +1,134 @@ +const { setDate, scrollWheel, expectDate, setMinimumDate, setMode } = require("../utils") + +const oneMinuteBeforeJanuary2 = new Date(2000, 0, 1, 23, 59, 0); + +describe('Minimum date', () => { + + before(async () => { + await device.reloadReactNative() + await element(by.text('Advanced')).tap() + }) + + beforeEach(async () => { + await setDate(oneMinuteBeforeJanuary2.toISOString()) + }) + + describe('cannot pass min date - mode: ', () => { + + describe('datetime', () => { + + before(async () => { + await setMode("datetime") + await setMinimumDate(oneMinuteBeforeJanuary2) + }) + + it('day wheel', async () => { + await scrollWheel(0, -2) + await expectDate("2000-01-01 23:59:00") + }) + + it('hour wheel', async () => { + await scrollWheel(1, -1) + await expectDate("2000-01-01 23:59:00") + }) + + it('minute wheel', async () => { + await scrollWheel(2, -1) + await expectDate("2000-01-01 23:59:00") + }) + + }) + + describe('date', () => { + + before(async () => { + await setMode("date") + await setMinimumDate(oneMinuteBeforeJanuary2) + }) + + it('month wheel', async () => { + await scrollWheel(0, -1) + await expectDate("2000-01-01 23:59:00") + }) + + it('date wheel', async () => { + await scrollWheel(1, -1) + await expectDate("2000-01-01 23:59:00") + }) + + it('year wheel', async () => { + await scrollWheel(2, -1) + await expectDate("2000-01-01 23:59:00") + }) + + }) + }) + + + describe('overshooting min date - mode:', () => { + + before(async () => { + await setMinimumDate(oneMinuteBeforeJanuary2) + }) + + describe('datetime', () => { + + before(async () => { + await setMode("datetime") + }) + + it('day wheel should not be possible to overshoot since it is not wrapping (no invalid dates exists)', async () => { + await scrollWheel(0, -1) + await expectDate("2000-01-01 23:59:00") + await scrollWheel(0, -1) + await expectDate("2000-01-01 23:59:00") + }) + + }) + + describe('date', () => { + + before(async () => { + await setMode("date") + }) + + it('overshooting month wheel should set all other wheels to minimum possible date', async () => { + await scrollWheel(0, -1) + await expectDate("2000-01-01 23:59:00") + }) + + it('overshooting date wheel should reverse to minimum possible date', async () => { + await scrollWheel(1, -5) + await expectDate("2000-01-01 23:59:00") + }) + + }) + + describe('time mode', () => { + + before(async () => { + await setMode("time") + await setMinimumDate(oneMinuteBeforeJanuary2) + }) + + it('overshooting hour wheel should reverse to minimum possible time', async () => { + await scrollWheel(0, -5) + await expectDate("2000-01-01 23:59:00") + }) + + it('overshooting minute wheel should reverse to minimum possible time', async () => { + await scrollWheel(1, -5) + await expectDate("2000-01-01 23:59:00") + }) + + it('overshooting am/pm wheel should reverse to minimum possible time', async () => { + await scrollWheel(2, -1) + await expectDate("2000-01-01 23:59:00") + }) + + }) + + + }) + +}) \ No newline at end of file diff --git a/examples/detox/e2e/tests/minuteInterval.spec.js b/examples/detox/e2e/tests/minuteInterval.spec.js new file mode 100644 index 0000000..fbbdb98 --- /dev/null +++ b/examples/detox/e2e/tests/minuteInterval.spec.js @@ -0,0 +1,34 @@ +const { scrollWheel, expectDate, setMinuteInterval } = require("../utils") + +const scrollMinuteWheel = () => scrollWheel(2, 1) + +describe('Minute interval', () => { + + before(async () => { + await device.reloadReactNative() + await element(by.text('Advanced')).tap() + }) + + it('1 minute (default)', async () => { + await setMinuteInterval(1) + await scrollMinuteWheel() + await expectDate("2000-01-01 00:01:00") + }) + + it('5 minutes', async () => { + await setMinuteInterval(5) + await scrollMinuteWheel() + await expectDate("2000-01-01 00:05:00") + }) + + it('15 minutes', async () => { + await setMinuteInterval(15) + await scrollMinuteWheel() + await expectDate("2000-01-01 00:15:00") + await scrollMinuteWheel() + await expectDate("2000-01-01 00:30:00") + await scrollMinuteWheel() + await expectDate("2000-01-01 00:45:00") + }) + +}) \ No newline at end of file diff --git a/examples/detox/e2e/tests/mode.spec.js b/examples/detox/e2e/tests/mode.spec.js new file mode 100644 index 0000000..9a95a21 --- /dev/null +++ b/examples/detox/e2e/tests/mode.spec.js @@ -0,0 +1,49 @@ +const { setMode } = require("../utils") + +describe('Modes', () => { + + before(async () => { + await device.reloadReactNative() + await element(by.text('Advanced')).tap() + }) + + it('datetime', async () => { + await setMode("datetime") + + await expect(element(by.id('day'))).toBeVisible() + await expect(element(by.id('minutes'))).toBeVisible() + await expect(element(by.id('hour'))).toBeVisible() + await expect(element(by.id('ampm'))).toBeVisible() + + await expect(element(by.id('month'))).toNotExist() + await expect(element(by.id('date'))).toNotExist() + await expect(element(by.id('year'))).toNotExist() + }) + + it('date', async () => { + await setMode("date") + + await expect(element(by.id('month'))).toBeVisible() + await expect(element(by.id('date'))).toBeVisible() + await expect(element(by.id('year'))).toBeVisible() + + await expect(element(by.id('day'))).toNotExist() + await expect(element(by.id('minutes'))).toNotExist() + await expect(element(by.id('hour'))).toNotExist() + await expect(element(by.id('ampm'))).toNotExist() + }) + + it('time', async () => { + await setMode("time") + + await expect(element(by.id('minutes'))).toBeVisible() + await expect(element(by.id('hour'))).toBeVisible() + await expect(element(by.id('ampm'))).toBeVisible() + + await expect(element(by.id('day'))).toNotExist() + await expect(element(by.id('month'))).toNotExist() + await expect(element(by.id('date'))).toNotExist() + await expect(element(by.id('year'))).toNotExist() + }) + +}) diff --git a/examples/detox/e2e/tests/scrollAround.spec.js b/examples/detox/e2e/tests/scrollAround.spec.js new file mode 100644 index 0000000..629318e --- /dev/null +++ b/examples/detox/e2e/tests/scrollAround.spec.js @@ -0,0 +1,45 @@ +const { scrollWheel, expectDate } = require("../utils") + + +describe('Scroll around', () => { + + before(async () => { + await device.reloadReactNative() + await element(by.text('Advanced')).tap() + }) + + it.skip('Hour wheel should scroll all way around and switch AM/PM when passing 12', async () => { + await scroll3HoursAndExpect("2000-01-01 03:00:00") + await scroll3HoursAndExpect("2000-01-01 06:00:00") + await scroll3HoursAndExpect("2000-01-01 09:00:00") + await scrollWheel(1, 2) + await expectDate("2000-01-01 11:00:00") + await scrollWheel(1, 2) + await expectDate("2000-01-01 13:00:00") + await scroll3HoursAndExpect("2000-01-01 16:00:00") + await scroll3HoursAndExpect("2000-01-01 19:00:00") + await scroll3HoursAndExpect("2000-01-01 22:00:00") + await scroll3HoursAndExpect("2000-01-01 01:00:00") + }) + + it('Minute wheel should be possible to scroll all way around', async () => { + await scrollWheel(2, 55) + await expectDate("2000-01-01 00:55:00") + await scrollWheel(2, 10) + await expectDate("2000-01-01 00:05:00") + }) + + it('Day wheel should change year when passing new year', async () => { + await scrollWheel(0, -1) + await expectDate("1999-12-31 00:00:00") + await scrollWheel(0, 1) + await expectDate("2000-01-01 00:00:00") + }) + + const scroll3HoursAndExpect = async (date) => { + await scrollWheel(1, 3) + await expectDate(date) + } + +}) + diff --git a/examples/detox/e2e/tests/wheelOrder.spec.js b/examples/detox/e2e/tests/wheelOrder.spec.js new file mode 100644 index 0000000..9a629d9 --- /dev/null +++ b/examples/detox/e2e/tests/wheelOrder.spec.js @@ -0,0 +1,95 @@ +const { scrollWheelWithIndexAndExpectDate, setMode, setLocale, setMaximumDate } = require("../utils") + + +describe('Wheel order', () => { + + before(async () => { + await device.reloadReactNative() + await element(by.text('Advanced')).tap() + await setMaximumDate("undefined") + }) + + describe('datetime', () => { + + before(async () => { + await setMode("datetime") + }) + + it('US', async () => { + await setLocale("en-US") + await scrollWheelWithIndexAndExpectDate(0, "2000-01-02 00:00:00") + await scrollWheelWithIndexAndExpectDate(1, "2000-01-01 01:00:00") + await scrollWheelWithIndexAndExpectDate(2, "2000-01-01 00:01:00") + await scrollWheelWithIndexAndExpectDate(3, "2000-01-01 12:00:00") + }) + + it('Korean', async () => { + await setLocale("ko-KR") + await scrollWheelWithIndexAndExpectDate(0, "2000-01-02 00:00:00") + await scrollWheelWithIndexAndExpectDate(1, "2000-01-01 12:00:00") + await scrollWheelWithIndexAndExpectDate(2, "2000-01-01 01:00:00") + await scrollWheelWithIndexAndExpectDate(3, "2000-01-01 00:01:00") + }) + + }) + + describe('date', () => { + + before(async () => { + await setMode("date") + }) + + it('US', async () => { + await setLocale("en-US") + await scrollWheelWithIndexAndExpectDate(0, "2000-02-01 00:00:00") + await scrollWheelWithIndexAndExpectDate(1, "2000-01-02 00:00:00") + await scrollWheelWithIndexAndExpectDate(2, "2001-01-01 00:00:00") + }) + + it('UK', async () => { + await setLocale("en-GB") + await scrollWheelWithIndexAndExpectDate(0, "2000-01-02 00:00:00") + await scrollWheelWithIndexAndExpectDate(1, "2000-02-01 00:00:00") + await scrollWheelWithIndexAndExpectDate(2, "2001-01-01 00:00:00") + }) + + it('Korean', async () => { + await setLocale("ko-KR") + await scrollWheelWithIndexAndExpectDate(0, "2001-01-01 00:00:00") + await scrollWheelWithIndexAndExpectDate(1, "2000-02-01 00:00:00") + await scrollWheelWithIndexAndExpectDate(2, "2000-01-02 00:00:00") + }) + + }) + + describe('time', () => { + + before(async () => { + await setMode("time") + }) + + it('US', async () => { + await setLocale("en-US") + await scrollWheelWithIndexAndExpectDate(0, "2000-01-01 01:00:00") + await scrollWheelWithIndexAndExpectDate(1, "2000-01-01 00:01:00") + await scrollWheelWithIndexAndExpectDate(2, "2000-01-01 12:00:00") + }) + + it('UK', async () => { + await setLocale("en-GB") + await scrollWheelWithIndexAndExpectDate(0, "2000-01-01 01:00:00") + await scrollWheelWithIndexAndExpectDate(1, "2000-01-01 00:01:00") + await scrollWheelWithIndexAndExpectDate(2, "2000-01-01 12:00:00") + }) + + it('Korean', async () => { + await setLocale("ko-KR") + await scrollWheelWithIndexAndExpectDate(0, "2000-01-01 12:00:00") + await scrollWheelWithIndexAndExpectDate(1, "2000-01-01 01:00:00") + await scrollWheelWithIndexAndExpectDate(2, "2000-01-01 00:01:00") + }) + + }) + + +}) diff --git a/examples/detox/e2e/utils.js b/examples/detox/e2e/utils.js new file mode 100644 index 0000000..a04120c --- /dev/null +++ b/examples/detox/e2e/utils.js @@ -0,0 +1,39 @@ + +const expectDate = async (date) => { + await expect(element(by.id('dateOutput'))).toHaveText(date) +} + +const reset = async () => { + await element(by.id('props/scroll')).tap() + await element(by.id('reset')).tap() +} + +const scrollWheel = async (index, times) => { + await element(by.id('props/scroll')).tap() + await element(by.id('wheelIndex')).replaceText(`${index}`) + await element(by.id('scrollTimes')).replaceText(`${times}`) + await element(by.id('doScroll')).tap() +} + +const changeProp = name => async value => { + await element(by.id('propName')).replaceText(name) + await element(by.id('propValue')).replaceText(`${value}`) + await element(by.id('changeProp')).tap() +} + +const scrollWheelWithIndexAndExpectDate = async (index, expectedDate) => { + await scrollWheel(index, 1) + await expectDate(expectedDate) + await reset() +} + +exports.setDate = changeProp("date") +exports.setLocale = changeProp("locale") +exports.setMinimumDate = changeProp("minimumDate") +exports.setMaximumDate = changeProp("maximumDate") +exports.setMinuteInterval = changeProp("minuteInterval") +exports.setMode = changeProp("mode") +exports.scrollWheel = scrollWheel +exports.expectDate = expectDate +exports.scrollWheelWithIndexAndExpectDate = scrollWheelWithIndexAndExpectDate +exports.reset = reset diff --git a/examples/detox/index.android.js b/examples/detox/index.android.js index f8b4649..5ac2ba1 100644 --- a/examples/detox/index.android.js +++ b/examples/detox/index.android.js @@ -1 +1 @@ -require('./app') +require('./src/App') diff --git a/examples/detox/index.js b/examples/detox/index.js index f8b4649..5ac2ba1 100644 --- a/examples/detox/index.js +++ b/examples/detox/index.js @@ -1 +1 @@ -require('./app') +require('./src/App') diff --git a/examples/detox/ios/example.xcodeproj/project.pbxproj b/examples/detox/ios/example.xcodeproj/project.pbxproj index 310a1e2..e37ab5d 100644 --- a/examples/detox/ios/example.xcodeproj/project.pbxproj +++ b/examples/detox/ios/example.xcodeproj/project.pbxproj @@ -5,6 +5,7 @@ }; objectVersion = 46; objects = { + /* Begin PBXBuildFile section */ 00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */; }; 00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */; }; @@ -20,8 +21,8 @@ 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; 146834051AC3E58100842450 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; }; 3953CBBA229AA464005DD98C /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3953CBB9229AA464005DD98C /* JavaScriptCore.framework */; }; - 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; }; 3A75CD301B1543908E566531 /* libRNDatePicker.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A630BBD6C5F543E09245F95D /* libRNDatePicker.a */; }; + 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -308,8 +309,8 @@ 46EE185A2047463E00FAAB0E /* RCTAnimation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTAnimation.xcodeproj; path = "../node_modules/react-native/Libraries/NativeAnimation/RCTAnimation.xcodeproj"; sourceTree = ""; }; 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = "../node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj"; sourceTree = ""; }; 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = "../node_modules/react-native/Libraries/Text/RCTText.xcodeproj"; sourceTree = ""; }; - E9E57B22E2C74DE5846A9803 /* RNDatePicker.xcodeproj */ = {isa = PBXFileReference; name = "RNDatePicker.xcodeproj"; path = "../node_modules/react-native-date-picker/ios/RNDatePicker.xcodeproj"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = wrapper.pb-project; explicitFileType = undefined; includeInIndex = 0; }; - A630BBD6C5F543E09245F95D /* libRNDatePicker.a */ = {isa = PBXFileReference; name = "libRNDatePicker.a"; path = "libRNDatePicker.a"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = archive.ar; explicitFileType = undefined; includeInIndex = 0; }; + A630BBD6C5F543E09245F95D /* libRNDatePicker.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNDatePicker.a; sourceTree = ""; }; + E9E57B22E2C74DE5846A9803 /* RNDatePicker.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNDatePicker.xcodeproj; path = "../node_modules/react-native-date-picker/ios/RNDatePicker.xcodeproj"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -460,6 +461,14 @@ name = Products; sourceTree = ""; }; + 5B8247D323EAED56002A0C87 /* Recovered References */ = { + isa = PBXGroup; + children = ( + A630BBD6C5F543E09245F95D /* libRNDatePicker.a */, + ); + name = "Recovered References"; + sourceTree = ""; + }; 78C398B11ACF4ADC00677621 /* Products */ = { isa = PBXGroup; children = ( @@ -505,6 +514,7 @@ 832341AE1AAA6A7D00B99B32 /* Libraries */, 00E356EF1AD99517003FC87E /* exampleTests */, 83CBBA001A601CBA00E9B192 /* Products */, + 5B8247D323EAED56002A0C87 /* Recovered References */, ); indentWidth = 2; sourceTree = ""; @@ -944,23 +954,23 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; DEAD_CODE_STRIPPING = NO; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "$(SRCROOT)/../node_modules/react-native-date-picker/ios/RNDatePicker", + ); INFOPLIST_FILE = example/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "\"$(SRCROOT)/example\"", + ); OTHER_LDFLAGS = ( "-ObjC", "-lc++", ); PRODUCT_BUNDLE_IDENTIFIER = com.wix.demo.react.native; PRODUCT_NAME = example; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "\"$(SRCROOT)/example\"", - ); - HEADER_SEARCH_PATHS = ( - "$(inherited)", - "$(SRCROOT)/../node_modules/react-native-date-picker/ios/RNDatePicker", - ); }; name = Debug; }; @@ -968,23 +978,23 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "$(SRCROOT)/../node_modules/react-native-date-picker/ios/RNDatePicker", + ); INFOPLIST_FILE = example/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "\"$(SRCROOT)/example\"", + ); OTHER_LDFLAGS = ( "-ObjC", "-lc++", ); PRODUCT_BUNDLE_IDENTIFIER = com.wix.demo.react.native; PRODUCT_NAME = example; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "\"$(SRCROOT)/example\"", - ); - HEADER_SEARCH_PATHS = ( - "$(inherited)", - "$(SRCROOT)/../node_modules/react-native-date-picker/ios/RNDatePicker", - ); }; name = Release; }; diff --git a/examples/detox/metro.config.js b/examples/detox/metro.config.js new file mode 100644 index 0000000..1c7ded2 --- /dev/null +++ b/examples/detox/metro.config.js @@ -0,0 +1,29 @@ +/** + * Metro configuration for React Native + * https://github.com/facebook/react-native + * + * @format + */ + +const path = require('path') +const blacklist = require('metro-config/src/defaults/blacklist') + +const reactNativeLib = path.resolve(__dirname, '../..') + +module.exports = { + watchFolders: [path.resolve(__dirname, 'node_modules'), reactNativeLib], + resolver: { + blacklistRE: blacklist([ + new RegExp(`${reactNativeLib}/node_modules/react-native/.*`), + ]), + }, + transformer: { + getTransformOptions: async () => ({ + transform: { + experimentalImportSupport: false, + inlineRequires: false, + }, + }), + }, + maxWorkers: 2, +} diff --git a/examples/detox/package.json b/examples/detox/package.json index 753fea9..ce67ea7 100644 --- a/examples/detox/package.json +++ b/examples/detox/package.json @@ -4,21 +4,23 @@ "private": true, "scripts": { "start": "react-native start", - "build:ios": "detox build --configuration ios.sim.debug", - "build:android-debug": "detox build --configuration android.emu.debug", - "build:android-release": "detox build --configuration android.emu.release", - "test:ios": "detox test --configuration ios.sim.debug", - "test:android-debug": "detox test --configuration android.emu.debug -l verbose", - "test:android-release": "detox test --configuration android.emu.release -l verbose", - "test:android-explicit-require": "detox test e2eExplicitRequire -c android.emu.release -l verbose --runner-config e2eExplicitRequire/mocha.opts", - "e2e:ios": "npm run build:ios && npm run test:ios", - "e2e:android-debug": "npm run build:android-debug && npm run test:android-debug", - "e2e:android-release": "npm run build:android-release && npm run test:android-release" + "postinstall": "yarn make-example-runnable", + "make-example-runnable": "(cd ../../ && npm i react react-native --no-save)", + "build:ios": "detox build --configuration ios.debug", + "build:android-debug": "detox build --configuration android.debug", + "build:android-ci": "detox build --configuration android.ci", + "test:ios": "detox test --configuration ios.debug", + "set-time-format": "adb shell settings put system time_12_24", + "test:android-24h-mode": "yarn set-time-format 24 && detox test --configuration android.debug e2e/tests/24h-mode/*.spec.js", + "test:android-24h-mode-ci": "yarn set-time-format 24 && detox test --configuration android.ci e2e/tests/24h-mode/*.spec.js --record-logs failing --record-videos failing --take-screenshots failing", + "test:android-12h-mode": "yarn set-time-format 12 && detox test --configuration android.debug e2e/tests/*.spec.js", + "test:android-12h-mode-ci": "yarn set-time-format 12 && detox test --configuration android.ci e2e/tests/*.spec.js --record-logs failing --record-videos failing --take-screenshots failing", + "test:android": "yarn test:android-12h-mode && yarn test:android-24h-mode", + "test:android-ci": "yarn test:android-12h-mode-ci && yarn test:android-24h-mode-ci" }, "dependencies": { "react": "16.8.3", - "react-native": "0.59.9", - "react-native-date-picker": "^2.6.1" + "react-native": "0.59.9" }, "devDependencies": { "detox": "^14.0.1", @@ -28,40 +30,30 @@ "test-runner": "mocha", "runner-config": "e2e/mocha.opts", "configurations": { - "ios.sim.release": { + "ios.release": { "binaryPath": "ios/build/Build/Products/Release-iphonesimulator/example.app", "build": "export RCT_NO_LAUNCH_PACKAGER=true && xcodebuild -project ios/example.xcodeproj -UseNewBuildSystem=NO -scheme example -configuration Release -sdk iphonesimulator -derivedDataPath ios/build -quiet", "type": "ios.simulator", "name": "iPhone X" }, - "ios.sim.debug": { + "ios.debug": { "binaryPath": "ios/build/Build/Products/Debug-iphonesimulator/example.app", "build": "xcodebuild -project ios/example.xcodeproj -UseNewBuildSystem=NO -scheme example -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build", "type": "ios.simulator", "name": "iPhone X" }, - "ios.none": { - "binaryPath": "ios/build/Build/Products/Debug-iphonesimulator/example.app", - "build": "xcodebuild -project ios/example.xcodeproj -UseNewBuildSystem=NO -scheme example -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build", - "type": "ios.none", - "name": "iPhone X", - "session": { - "server": "ws://localhost:8099", - "sessionId": "com.wix.demo.react.native" - } - }, - "android.emu.debug": { + "android.ci": { "binaryPath": "android/app/build/outputs/apk/debug/app-debug.apk", "build": "cd android ; ./gradlew assembleDebug assembleAndroidTest -DtestBuildType=debug ; cd -", "type": "android.emulator", - "name": "Nexus_4_API_28" + "name": "emu" }, - "android.emu.release": { - "binaryPath": "android/app/build/outputs/apk/release/app-release.apk", - "build": "cd android ; ./gradlew assembleRelease assembleAndroidTest -DtestBuildType=release ; cd -", + "android.debug": { + "binaryPath": "android/app/build/outputs/apk/debug/app-debug.apk", + "build": "cd android ; ./gradlew assembleDebug assembleAndroidTest -DtestBuildType=debug ; cd -", "type": "android.emulator", - "name": "Nexus_4_API_28" + "name": "Pixel_2_API_29" } } } -} +} \ No newline at end of file diff --git a/examples/detox/src/App.js b/examples/detox/src/App.js new file mode 100644 index 0000000..1ca2119 --- /dev/null +++ b/examples/detox/src/App.js @@ -0,0 +1,84 @@ +import React, { Component } from 'react' +import { ScrollView, AppRegistry, StyleSheet, Text, TouchableOpacity } from 'react-native' +import examples from './examples' + +class App extends Component { + state = { + picker: undefined, + backgroundColor: '#ffffff', + } + + render() { + return ( + + {!this.state.picker && 'Examples'} + {!this.state.picker && this.renderButtons()} + {!!this.state.picker && this.renderBackButton()} + {!!this.state.picker && this.renderPicker()} + + ) + } + + setBackgroundColor = backgroundColor => this.setState({ backgroundColor }) + + renderPicker = () => { + const Picker = examples[this.state.picker].component + return ( + + ) + } + + renderButtons = () => + Object.keys(examples) + .filter(key => key !== this.state.picker) + .map(this.renderButton) + + renderButton = key => ( + this.setState({ picker: key })} + style={{ margin: 10 }} + > + {examples[key].buttonTitle} + + ) + + renderBackButton = key => ( + this.setState({ picker: undefined })} + style={{ margin: 10, position: 'absolute', top: 0, left: 10 }} + > + Back + + ) +} + +const styles = StyleSheet.create({ + container: { + paddingTop: 15, + borderWidth: 1, + }, + content: { + alignItems: 'center', + }, + text: { + color: 'dodgerblue', + fontSize: 16, + }, + header: { + color: 'black', + fontSize: 22, + margin: 20, + }, +}) + +AppRegistry.registerComponent('example', () => App) \ No newline at end of file diff --git a/examples/detox/src/CustomPropValue.js b/examples/detox/src/CustomPropValue.js new file mode 100644 index 0000000..0309286 --- /dev/null +++ b/examples/detox/src/CustomPropValue.js @@ -0,0 +1,49 @@ +import React, { useState } from 'react' +import { Button, TextInput, Text, View, TouchableOpacity } from 'react-native' + +export default function CustomPropValue(props) { + const [propName, setPropName] = useState("") + const [propValue, setPropValue] = useState("") + + const getPropValue = () => { + if (propValue === "undefined") return undefined + if (propName === "minuteInterval") return parseInt(propValue) + if (["date", "maximumDate", "minimumDate"].includes(propName)) return new Date(propValue) + return propValue + } + + return ( + + + Prop name + + Prop value + + + props.changeProp({ propName, propValue: getPropValue() })} + >Change + + ) +} + +const input = { + height: 30, + borderColor: 'gray', + borderWidth: 0.5, + margin: 2, + padding: 0, + alignItems: "center", + textAlign: "center" +} \ No newline at end of file diff --git a/examples/detox/src/PropButton.js b/examples/detox/src/PropButton.js new file mode 100644 index 0000000..2822ed8 --- /dev/null +++ b/examples/detox/src/PropButton.js @@ -0,0 +1,6 @@ +import React, { Component } from 'react' +import { Button } from 'react-native' + +export const PropButton = ({ title, value, onChange }) => ( +
iOS