blob: 2d5c3f3fab8c5cb88b480a4ae042cbc1da684348 [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// the following ignore is needed for downgraded analyzer (casts to JSObject).
// ignore_for_file: unnecessary_cast
import 'dart:async';
import 'dart:js_interop';
import 'dart:js_interop_unsafe';
import 'package:flutter_test/flutter_test.dart';
import 'package:google_identity_services_web/id.dart';
import 'package:google_identity_services_web/oauth2.dart';
import 'package:web/web.dart' as web;
/// Function that lets us expect that a JSObject has a [name] property that matches [matcher].
///
/// Use [createExpectConfigValue] to create one of this functions associated with
/// a specific [JSObject].
typedef ExpectConfigValueFn = void Function(String name, Object? matcher);
/// Creates a [ExpectConfigValueFn] for the `config` [JSObject].
ExpectConfigValueFn createExpectConfigValue(JSObject config) {
return (String name, Object? matcher) {
expect(config[name], matcher, reason: name);
};
}
/// A matcher that checks if: value typeof [thing] == true (in JS).
///
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof
Matcher isAJs(String thing) => isA<JSAny?>()
.having((JSAny? p0) => p0.typeofEquals(thing), 'typeof "$thing"', isTrue);
/// Installs mock-gis.js in the page.
/// Returns a future that completes when the 'load' event of the script fires.
Future<void> installGisMock() {
final Completer<void> completer = Completer<void>();
final web.HTMLScriptElement script =
web.document.createElement('script') as web.HTMLScriptElement;
script.src = 'mock-gis.js';
script.type = 'module';
script.addEventListener(
'load',
(JSAny? _) {
completer.complete();
}.toJS);
web.document.head!.appendChild(script);
return completer.future;
}
/// Fakes authorization with the given scopes.
Future<TokenResponse> fakeAuthZWithScopes(List<String> scopes) {
final StreamController<TokenResponse> controller =
StreamController<TokenResponse>();
final TokenClient client = oauth2.initTokenClient(TokenClientConfig(
client_id: 'for-tests',
callback: controller.add,
scope: scopes,
));
setMockTokenResponse(client, 'some-non-null-auth-token-value');
client.requestAccessToken();
return controller.stream.first;
}
/// Allows calling a `setMockTokenResponse` method (added by mock-gis.js)
extension on TokenClient {
external void setMockTokenResponse(JSString? token);
}
/// Sets a mock TokenResponse value in a [client].
void setMockTokenResponse(TokenClient client, [String? authToken]) {
client.setMockTokenResponse(authToken?.toJS);
}
/// Allows calling a `setMockCredentialResponse` method (set by mock-gis.js)
extension on GoogleAccountsId {
external void setMockCredentialResponse(
JSString credential,
JSString select_by, //ignore: non_constant_identifier_names
);
}
/// Sets a mock credential response in `google.accounts.id`.
void setMockCredentialResponse([String value = 'default_value']) {
_getGoogleAccountsId().setMockCredentialResponse(value.toJS, 'auto'.toJS);
}
GoogleAccountsId _getGoogleAccountsId() {
return _getDeepProperty<GoogleAccountsId>(
web.window as JSObject, 'google.accounts.id');
}
// Attempts to retrieve a deeply nested property from a jsObject (or die tryin')
T _getDeepProperty<T>(JSObject jsObject, String deepProperty) {
final List<String> properties = deepProperty.split('.');
return properties.fold<JSObject?>(
jsObject,
(JSObject? jsObj, String prop) => jsObj?[prop] as JSObject?,
) as T;
}