Skip to content

Commit

Permalink
feat: stripe js (#1052)
Browse files Browse the repository at this point in the history
* feat: stripe js library

* test: add tests for api and endpoints

* fix: path workflow

* fix: publish stripe_js

* ci: fix workflow

* fix: add stripe_js docs

* fix: change license

* fix: update examples

* fix: analyze warnings
  • Loading branch information
jamesblasco authored Dec 10, 2022
1 parent 43635ec commit f4e03de
Show file tree
Hide file tree
Showing 214 changed files with 39,485 additions and 4,040 deletions.
58 changes: 58 additions & 0 deletions .github/workflows/stripe_js.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
name: stripe_js

on:
push:
branches: [master]
paths-ignore:
- "docs/**"
- "website/**"
- "**.md"
pull_request:
branches: ['**']
paths-ignore:
- "docs/**"
- "website/**"
- "**.md"

jobs:
build:
defaults:
run:
working-directory: packages/stripe_js

runs-on: ubuntu-latest

steps:
- name: 📚 Git Checkout
uses: actions/checkout@v3

- name: 🎯 Setup Dart
uses: dart-lang/setup-dart@v1

- name: 📦 Install Dependencies
run: dart pub get

- name: "Set env keys"
env:
STRIPE_PUBLISHABLE_KEY: ${{ secrets.STRIPE_PUBLISHABLE_KEY }}
run: |
cd ../../
./.github/workflows/scripts/env-files.sh
- name: ✨ Check Formatting
run: dart format --set-exit-if-changed .

- name: 🕵️ Analyze
run: dart analyze --fatal-infos --fatal-warnings lib test

- name: 🧪 Run Tests
run: |
dart pub global activate coverage
dart test -j 4 --coverage=coverage --platform=chrome && dart pub global run coverage:format_coverage --lcov --in=coverage --out=coverage/lcov.info --packages=.dart_tool/package_config.json --report-on=lib
- name: 📊 Check Code Coverage
uses: VeryGoodOpenSource/very_good_coverage@v2
with:
path: packages/stripe_js/coverage/lcov.info
exclude: "lib/**/*.g.dart lib/**/*.freezed.dart"
min_coverage: 0
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,10 @@ build/
lcov.info

**/pubspec.lock

**/server/package-lock.json

**/node_modules/
/test-results/
/playwright-report/
/playwright/.cache/
22 changes: 22 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,27 @@
"request": "launch",
"type": "dart",
},
{
"name": "Stripe.js web tests",
"request": "launch",
"type": "dart",
"program": "packages/stripe_js/test",
"args": [
"-p",
"chrome",
"-t",
"browser"
], // Additional args to pass
"codeLens": {
"for": [
"run-test",
"run-test-file",
"debug-test",
"debug-test-file"
],
"path": "packages/stripe_js/test",
"title": "${debugType} (chrome)"
},
},
]
}
1 change: 0 additions & 1 deletion example/lib/screens/checkout/checkout_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import 'package:flutter/material.dart';
import 'package:stripe_checkout/stripe_checkout.dart';
import 'package:http/http.dart' as http;


class CheckoutScreenExample extends StatefulWidget {
CheckoutScreenExample({
Key? key,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ class _FinancialConnectionsScreenState
}
}
}

Future<void> _collectBankToken(BuildContext context) async {
// Precondition:
// 1. Make sure to create a financial connection session on the backend and
Expand Down Expand Up @@ -117,7 +118,6 @@ class _FinancialConnectionsScreenState
},
text: 'Collect financial account',
),

LoadingButton(
onPressed: () async {
await _collectBankToken(context);
Expand Down
14 changes: 8 additions & 6 deletions example/lib/screens/others/cvc_re_collection_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,13 @@ class _CVCReCollectionScreenState extends State<CVCReCollectionScreen> {
final paymentMethod = await _fetchPaymentIntentWithPaymentMethod();

if (paymentMethod['error'] != null) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Error code: ${paymentMethod['error']}')));
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error code: ${paymentMethod['error']}')));
return;
}

ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text('Success!: The payment was confirmed successfully!')));
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('Success!: The payment was confirmed successfully!')));
}

Future<void> _paySynchronously() async {
Expand All @@ -83,10 +84,11 @@ class _CVCReCollectionScreenState extends State<CVCReCollectionScreen> {
);
log('paymentIntent $paymentIntent');
if (paymentIntent['error'] != null) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Error code: ${paymentIntent['error']}')));
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error code: ${paymentIntent['error']}')));
} else if (paymentIntent['succeeded'] == true) {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text('Success!: The payment was confirmed successfully!')));
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('Success!: The payment was confirmed successfully!')));
} else {
// Handle other statuses accordingly
throw UnimplementedError();
Expand Down
10 changes: 5 additions & 5 deletions example/lib/screens/others/legacy_token_bank_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,11 @@ class _LegacyTokenBankScreenState extends State<LegacyTokenBankScreen> {
try {
// 1. Gather customer billing information (ex. email)
final params = BankAccountTokenParams(
currency: 'EUR',
country: 'DE',
accountNumber: _controller.text,
accountHolderName: 'Dash Flutter',
accountHolderType: BankAccountHolderType.Individual,
currency: 'EUR',
country: 'DE',
accountNumber: _controller.text,
accountHolderName: 'Dash Flutter',
accountHolderType: BankAccountHolderType.Individual,
); // mocked data for tests

// 2. Create payment method
Expand Down
9 changes: 3 additions & 6 deletions example/lib/screens/others/legacy_token_card_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,9 @@ class _LegacyTokenCardScreenState extends State<LegacyTokenCardScreen> {
); // mocked data for tests

// 2. Create payment method
final tokenData =
await Stripe.instance.createToken(CreateTokenParams.card(
params: CardTokenParams(
address: address,
currency: 'USD'
)));
final tokenData = await Stripe.instance.createToken(
CreateTokenParams.card(
params: CardTokenParams(address: address, currency: 'USD')));
setState(() {
this.tokenData = tokenData;
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ class _SetupFuturePaymentScreenState extends State<SetupFuturePaymentScreen> {
// 3. Confirm setup intent

final setupIntentResult = await Stripe.instance.confirmSetupIntent(
paymentIntentClientSecret: clientSecret,
paymentIntentClientSecret: clientSecret,
params: PaymentMethodParams.card(
paymentMethodData: PaymentMethodData(
billingDetails: billingDetails,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import 'package:flutter/material.dart';
import 'package:stripe_example/config.dart';

import 'package:http/http.dart' as http;
import 'platforms/payment_element.dart'
if (dart.library.js) 'platforms/payment_element_web.dart';
import 'package:stripe_example/widgets/loading_button.dart';

class PaymentElementExample extends StatefulWidget {
@override
Expand Down Expand Up @@ -44,32 +47,29 @@ class _ThemeCardExampleState extends State<PaymentElementExample> {
),
body: Column(
children: [
// Container(
// height: 150,
// alignment: Alignment.center,
// padding: EdgeInsets.symmetric(vertical: 20, horizontal: 20),
// child: clientSecret != null ? PaymentElement(
// autofocus: true,
// enablePostalCode: true,
// onCardChanged: (_) {},
// clientSecret: clientSecret ?? '',
// ) : Center(
// child: CircularProgressIndicator(),
// )
// )
Container(
child: clientSecret != null
? PlatformPaymentElement(clientSecret)
: Center(child: CircularProgressIndicator())),
LoadingButton(onPressed: pay, text: 'Pay'),
],
),
);
}

Future<String> createPaymentIntent() async {
final url = Uri.parse('$kApiUrl/universal-payment');
final url = Uri.parse('$kApiUrl/create-payment-intent');
final response = await http.post(
url,
headers: {
'Content-Type': 'application/json',
},
body: json.encode({}),
body: json.encode({
'currency': 'usd',
'amount': 1099,
'payment_method_types': ['card'],
'request_three_d_secure': 'any',
}),
);
return json.decode(response.body)['clientSecret'];
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import 'package:flutter/widgets.dart';

Future<void> pay() async {
throw UnimplementedError();
}

class PlatformPaymentElement extends StatelessWidget {
const PlatformPaymentElement(this.clientSecret);

final String? clientSecret;

@override
Widget build(BuildContext context) {
return Container();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import 'package:flutter/widgets.dart';
import 'package:flutter_stripe_web/flutter_stripe_web.dart';

import '../../../checkout/platforms/stripe_checkout_web.dart';

Future<void> pay() async {
await WebStripe().confirmPaymentElement(
ConfirmPaymentElementOptions(
confirmParams: ConfirmPaymentParams(return_url: getReturnUrl()),
),
);
}

class PlatformPaymentElement extends StatelessWidget {
const PlatformPaymentElement(this.clientSecret);

final String? clientSecret;

@override
Widget build(BuildContext context) {
return PaymentElement(
autofocus: true,
enablePostalCode: true,
onCardChanged: (_) {},
clientSecret: clientSecret ?? '',
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ class AliPayScreen extends StatelessWidget {
// 2. use the client secret to confirm the payment and handle the result.
try {
await Stripe.instance.confirmPayment(
paymentIntentClientSecret: clientSecret,
data: PaymentMethodParams.alipay(
paymentMethodData: const PaymentMethodData(),
paymentIntentClientSecret: clientSecret,
data: PaymentMethodParams.alipay(
paymentMethodData: const PaymentMethodData(),
),
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,8 @@ class _AubecsExampleState extends State<AubecsExample> {
// 2. use the client secret to confirm the payment and handle the result.
try {
await Stripe.instance.confirmPayment(
paymentIntentClientSecret: clientSecret,
data: PaymentMethodParams.aubecs(
paymentIntentClientSecret: clientSecret,
data: PaymentMethodParams.aubecs(
paymentMethodData: PaymentMethodDataAubecs(formDetails: _details!),
),
);
Expand Down
4 changes: 2 additions & 2 deletions example/lib/screens/regional_payment_methods/fpx_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ class FpxScreen extends StatelessWidget {
// 2. use the client secret to confirm the payment and handle the result.
try {
await Stripe.instance.confirmPayment(
paymentIntentClientSecret: clientSecret,
data: PaymentMethodParams.fpx(
paymentIntentClientSecret: clientSecret,
data: PaymentMethodParams.fpx(
paymentMethodData: PaymentMethodDataFpx(
testOfflineBank: false,
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ class GrabPayScreen extends StatelessWidget {
// 3. use the client secret to confirm the payment and handle the result.
try {
await Stripe.instance.confirmPayment(
paymentIntentClientSecret: clientSecret,
data: PaymentMethodParams.grabPay(
paymentIntentClientSecret: clientSecret,
data: PaymentMethodParams.grabPay(
paymentMethodData: PaymentMethodData(
billingDetails: billingDetails,
),
Expand Down
10 changes: 6 additions & 4 deletions example/lib/screens/regional_payment_methods/ideal_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,10 @@ class IdealScreen extends StatelessWidget {
// 2. use the client secret to confirm the payment and handle the result.
try {
await Stripe.instance.confirmPayment(
paymentIntentClientSecret: clientSecret,
data: PaymentMethodParams.ideal(
paymentMethodData: PaymentMethodDataIdeal(bankName: kIsWeb ? 'revolut' : null),
paymentIntentClientSecret: clientSecret,
data: PaymentMethodParams.ideal(
paymentMethodData:
PaymentMethodDataIdeal(bankName: kIsWeb ? 'revolut' : null),
),
);

Expand All @@ -56,7 +57,8 @@ class IdealScreen extends StatelessWidget {
if (e is StripeException) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Error from Stripe: ${e.error.localizedMessage ?? e.error.code}'),
content: Text(
'Error from Stripe: ${e.error.localizedMessage ?? e.error.code}'),
),
);
} else {
Expand Down
Loading

0 comments on commit f4e03de

Please sign in to comment.