Skip to content

Commit

Permalink
add integration test infrastructure (#62)
Browse files Browse the repository at this point in the history
* WIP: add integration test infrastructure

* fix env-files.sh

* fix working directory

* debug

* try different ip method

* try different IP method

* try different IP method

* start Android emulator

* start Android emulator

* fix analyze issue, cleanup

* increase timeout

* create payment method integration test

* integrate native instrumentation for android

this is needed to run it on firebase

* add ios native configuration

this is needed to run the test on firebase

* feat: payment method tests

* fix: remane integration test job

* fix indent worflow file

* fix isEmpty fields

* hide app_test.dart test

* fix test

* fix unit tests

* try to fix workflow

* fix action

* run it on macos-latest

* update tests, cleanup

* update tests, cleanup

Co-authored-by: Remon <remon@hey.com>
Co-authored-by: Jaime Blasco <jaimeblasco97@gmail.com>
Co-authored-by: Rémon <remonhelmond@gmail.com>
  • Loading branch information
4 people committed Jul 15, 2022
1 parent 3339623 commit 416d9df
Show file tree
Hide file tree
Showing 19 changed files with 664 additions and 26 deletions.
72 changes: 63 additions & 9 deletions .github/workflows/all_plugins.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,27 +27,27 @@ jobs:
- name: "Install Tools"
run: |
./.github/workflows/scripts/install-tools.sh
- name: "Bootstrap Workspace"
run: melos bootstrap

- name: "Set env keys"
env:
env:
STRIPE_PUBLISHABLE_KEY: ${{ secrets.STRIPE_PUBLISHABLE_KEY }}
run: |
./.github/workflows/scripts/env-files.sh
- name: "Run Analyze"
run: melos run analyze

- name: "Pub Check"
run: |
melos exec -c 1 --no-private --ignore="*example*" -- \
flutter pub publish --dry-run
test:
name: test
timeout-minutes: 15
timeout-minutes: 30
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
Expand All @@ -58,15 +58,69 @@ jobs:
- name: "Install Tools"
run: |
./.github/workflows/scripts/install-tools.sh
- name: "Bootstrap Workspace"
run: melos bootstrap

- name: "Set env keys"
env:
env:
STRIPE_PUBLISHABLE_KEY: ${{ secrets.STRIPE_PUBLISHABLE_KEY }}
STRIPE_SECRET_KEY: ${{ secrets.STRIPE_SECRET_KEY }}
run: |
./.github/workflows/scripts/env-files.sh
- name: "Run unittest"
run: melos run unittest
run: melos run unittest


integration_test:
name: Integration test
timeout-minutes: 30
runs-on: macos-latest
steps:
- uses: actions/checkout@v2

- name: Set up Java version
uses: actions/setup-java@v1
with:
java-version: '11'

- uses: subosito/flutter-action@v1
with:
channel: 'stable'

- name: "Install Tools"
run: |
./.github/workflows/scripts/install-tools.sh
- name: "Bootstrap Workspace"
run: melos bootstrap

- name: "Set env keys"
env:
STRIPE_PUBLISHABLE_KEY: ${{ secrets.STRIPE_PUBLISHABLE_KEY }}
STRIPE_SECRET_KEY: ${{ secrets.STRIPE_SECRET_KEY }}
run: |
./.github/workflows/scripts/env-files.sh
- name: "Start dev server"
working-directory: example/server
run: npm install && (npm run start:dev &)

- name: "Set IP address"
working-directory: example
run: echo "const kApiUrl='''$(ifconfig | grep 'inet ' | grep -v '127.0.0.1' | awk '{print $2}')''';" > integration_test/ip.dart

- name: "Print ip.dart"
working-directory: example
run: cat integration_test/ip.dart

- name: "Run integration test Android"
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: 29
working-directory: example
script: |
sleep 15;
flutter drive --driver test_driver/integration_test.dart --target=integration_test/run_all_tests.dart;
cd android && ./gradlew :app:connectedDebugAndroidTest;
17 changes: 16 additions & 1 deletion .github/workflows/scripts/env-files.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,20 @@ else
sed -i "s/<ADD_YOUR_KEY_HERE>/$STRIPE_PUBLISHABLE_KEY/" ./.env.dart
fi

cd ..
cp lib/.env.dart integration_test/.env.dart

# TODO: ADD SERVER .ENV
cd server
cp .env.example .env

# The syntax of -i is one difference between GNU sed and sed from mac os
if [[ "$OSTYPE" == "darwin"* ]]; then
sed -i '' "s/<ADD_YOUR_KEY_HERE>/$STRIPE_PUBLISHABLE_KEY/" ./.env
else
sed -i "s/<ADD_YOUR_KEY_HERE>/$STRIPE_PUBLISHABLE_KEY/" ./.env
fi
if [[ "$OSTYPE" == "darwin"* ]]; then
sed -i '' "s/<ADD_YOUR_SECRET_KEY_HERE>/$STRIPE_SECRET_KEY/" ./.env
else
sed -i "s/<ADD_YOUR_SECRET_KEY_HERE>/$STRIPE_SECRET_KEY/" ./.env
fi
3 changes: 3 additions & 0 deletions example/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ android {
targetSdkVersion 31
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

buildTypes {
Expand All @@ -59,4 +60,6 @@ dependencies {
implementation 'com.tencent.mm.opensdk:wechat-sdk-android-without-mta:6.7.0'
implementation 'com.google.android.gms:play-services-wallet:19.1.0'
implementation 'com.stripe:stripe-wechatpay:17.1.0'
androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import com.facebook.react.bridge.ReadableMap
import org.junit.Test

class BridgeTest {

@Test
fun testGetDouble() {
val map = ReadableMap(mapOf("test" to 1.1))
assert(map.getDouble("test") == 1.1)
}
@Test
fun testGetIntShouldFail() {
val map = ReadableMap(mapOf("test" to 1.1))
var exception: Exception? = null
try {
map.getInt("test")
} catch (e: Exception) {
exception = e
}
assert(exception!!.message == "We've got a double here")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.flutter.stripe.example

import androidx.test.rule.ActivityTestRule
import com.facebook.react.bridge.ReadableMap
import dev.flutter.plugins.integration_test.FlutterTestRunner
import org.json.JSONObject
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(FlutterTestRunner::class)
class MainActivityTest {
@get:Rule
var rule: ActivityTestRule<MainActivity> =
ActivityTestRule(MainActivity::class.java, true, false)
}
121 changes: 121 additions & 0 deletions example/integration_test/app_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:flutter_stripe/flutter_stripe.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:http/http.dart' as http;
import 'package:integration_test/integration_test.dart';

import '.env.dart';
import 'ip.dart';

void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();

Stripe.publishableKey = stripePublishableKey;
Stripe.merchantIdentifier = 'MerchantIdentifier';
Stripe.urlScheme = 'flutterstripe';

group('Payment sheet', () {
testWidgets('init payment sheet', (_) async {
// 1. create payment intent on the server
final _paymentSheetData = await _createTestPaymentSheet();

// 2. initialize the payment sheet
await Stripe.instance.initPaymentSheet(
paymentSheetParameters: SetupPaymentSheetParameters(
applePay: true,
googlePay: true,
style: ThemeMode.dark,
testEnv: true,
merchantCountryCode: 'DE',
merchantDisplayName: 'Flutter Stripe Store Demo',
customerId: _paymentSheetData['customer'],
paymentIntentClientSecret: _paymentSheetData['paymentIntent'],
customerEphemeralKeySecret: _paymentSheetData['ephemeralKey'],
),
);

expect(true, _paymentSheetData['paymentIntent'] != null);
});
});

group('Create payment method', () {
testWidgets('create payment method', (tester) async {
// 1. create some billing details
final billingDetails = BillingDetails(
name: 'Name',
email: 'email@flutterstripe.com',
phone: '+48888000888',
address: Address(
city: 'Houston',
country: 'US',
line1: '1459 Circle Drive',
line2: '',
state: 'Texas',
postalCode: '77063',
),
);

// 2. update card details
// because of https://github.com/flutter/flutter/issues/34345
// we cannot use cardfield
final cardDetails = CardDetails(
number: '4242424242424242',
cvc: '424',
expirationMonth: 04,
expirationYear: 2025,
);
await Stripe.instance.dangerouslyUpdateCardDetails(cardDetails);

final paymentMethod = await Stripe.instance.createPaymentMethod(
PaymentMethodParams.card(
paymentMethodData: PaymentMethodData(
billingDetails: billingDetails,
),
),
);

// 3. create intent on the server
final paymentIntentResult = await _createNoWebhookPayEndpointMethod(paymentMethod.id);
expect(paymentIntentResult['status'], 'succeeded');
});
});
}

Future<Map<String, dynamic>> _createTestPaymentSheet() async {
// ifconfig | grep 'inet ' | grep -v '127.0.0.1' | awk '{print $2}' could return multiple IPs, divided by new line - use the last one
final ipAddress = kApiUrl.split('\n').last.trim();
print('IP Address of the server: $ipAddress');
final url = Uri.parse('http://$ipAddress:4242/payment-sheet');
final response = await http.post(
url,
headers: {
'Content-Type': 'application/json',
},
body: json.encode({
'a': 'a',
}),
);
return json.decode(response.body);
}

Future<Map<String, dynamic>> _createNoWebhookPayEndpointMethod(String paymentMethodId) async {
final ipAddress = kApiUrl.split('\n').last.trim();
final url = Uri.parse('http://$ipAddress:4242/pay-without-webhooks');
final response = await http.post(
url,
headers: {
'Content-Type': 'application/json',
},
body: json.encode({
'useStripeSdk': true,
'paymentMethodId': paymentMethodId,
'currency': 'usd',
'items': [
{'id': 'id'}
]
}),
);
return json.decode(response.body);
}
1 change: 1 addition & 0 deletions example/integration_test/ip.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
const kApiUrl = '''192.168.0.1''';
Loading

0 comments on commit 416d9df

Please sign in to comment.