Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FEDX-126 FED-1719 Null Safety Migration #63

Merged
merged 33 commits into from
Nov 28, 2023
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
65d968a
Remove @dart 2.7 comments
sydneyjodon-wk Jun 14, 2023
be7cb23
Add hints part 1
sydneyjodon-wk Jun 15, 2023
afaea6e
Apply migration
sydneyjodon-wk Jun 16, 2023
e6794d3
Fix warnings and lints
sydneyjodon-wk Jun 16, 2023
a6f489a
Indent matrix key
sydneyjodon-wk Jun 16, 2023
1fb1844
Update dep override
sydneyjodon-wk Jun 16, 2023
ffb26fb
Fix query tests
sydneyjodon-wk Jun 21, 2023
afa5c15
Merge branch 'fix-actions-tests' into null-safety
sydneyjodon-wk Jun 22, 2023
7f7850c
Fix isDisabled
sydneyjodon-wk Jun 23, 2023
a7a7689
Format
sydneyjodon-wk Jun 23, 2023
c22e82f
Update dependency to react-dart 7
sydneyjodon-wk Nov 13, 2023
844e7b7
Merge branch 'master' into null-safety
sydneyjodon-wk Nov 13, 2023
62adb47
Fix analysis errors
sydneyjodon-wk Nov 13, 2023
083aa73
Run CI on 2.19 as well
sydneyjodon-wk Nov 13, 2023
ebbcabc
Run CI on 2.19 as well
sydneyjodon-wk Nov 13, 2023
fab1044
Fix hints
sydneyjodon-wk Nov 13, 2023
976b962
Change CI to 2.19.6
sydneyjodon-wk Nov 13, 2023
8f45e91
Fix warnings
sydneyjodon-wk Nov 13, 2023
25f3e5c
Format
sydneyjodon-wk Nov 13, 2023
e552d85
Fix diff
sydneyjodon-wk Nov 13, 2023
417a754
Remove 2.18 CI check
sydneyjodon-wk Nov 13, 2023
e7426ca
Fix casting
sydneyjodon-wk Nov 13, 2023
7b76f36
Fix Future casting
sydneyjodon-wk Nov 13, 2023
fb14bc2
Make screen.container non-nullable
sydneyjodon-wk Nov 15, 2023
afbcab2
Refactor waitFor onDone function
sydneyjodon-wk Nov 15, 2023
a02b547
Reformat accessibility helpers
sydneyjodon-wk Nov 15, 2023
951a135
Update fireEventByName
sydneyjodon-wk Nov 16, 2023
9566232
Add prettyDom test
sydneyjodon-wk Nov 20, 2023
fecb0b1
Update dom queries
sydneyjodon-wk Nov 21, 2023
07a008f
Update within
sydneyjodon-wk Nov 21, 2023
42410ab
Update matchers
sydneyjodon-wk Nov 21, 2023
17a41cf
Clean up other utils
sydneyjodon-wk Nov 21, 2023
6bc0767
Address feedback
sydneyjodon-wk Nov 28, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions .github/workflows/build_and_deploy_docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
strategy:
fail-fast: false
matrix:
sdk: [ 2.18.7 ]
sdk: [ 2.19.6 ]
steps:
- uses: actions/checkout@v3
- uses: dart-lang/setup-dart@v1
Expand All @@ -32,7 +32,7 @@ jobs:
- id: build-docs
name: Build Docs
run: dart pub get && dart doc .
if: ${{ matrix.sdk == '2.18.7' }}
if: ${{ matrix.sdk == '2.19.6' }}

# Upload the artifact as required by actions/deploy-pages
- name: Archive Dartdoc Artifact
Expand All @@ -49,5 +49,3 @@ jobs:
with:
artifact_name: dartdoc
if: ${{ steps.build-docs.outcome == 'success' && steps.archive-dartdoc-artifact.outcome == 'success' && github.event_name == 'push' }}


2 changes: 1 addition & 1 deletion .github/workflows/dart_ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
strategy:
fail-fast: false
matrix:
sdk: [ 2.18.7 ]
sdk: [ 2.19.6 ]
steps:
- uses: actions/checkout@v2
- uses: dart-lang/setup-dart@v1
Expand Down
2 changes: 0 additions & 2 deletions lib/dom/accessibility.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// @dart = 2.7

// Copyright 2021 Workiva Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
Expand Down
2 changes: 0 additions & 2 deletions lib/dom/async.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// @dart = 2.7

// Copyright 2021 Workiva Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
Expand Down
2 changes: 0 additions & 2 deletions lib/dom/configure.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// @dart = 2.7

// Copyright 2021 Workiva Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
Expand Down
2 changes: 0 additions & 2 deletions lib/dom/debugging.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// @dart = 2.7

// Copyright 2021 Workiva Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
Expand Down
2 changes: 0 additions & 2 deletions lib/dom/events.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// @dart = 2.7

// Copyright 2021 Workiva Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
Expand Down
2 changes: 0 additions & 2 deletions lib/dom/queries.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// @dart = 2.7

// Copyright 2021 Workiva Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
Expand Down
2 changes: 0 additions & 2 deletions lib/matchers.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// @dart = 2.7

// Copyright 2021 Workiva Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
Expand Down
2 changes: 0 additions & 2 deletions lib/react/react.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// @dart = 2.7

// Copyright 2021 Workiva Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
Expand Down
2 changes: 0 additions & 2 deletions lib/react_testing_library.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// @dart = 2.7

// Copyright 2021 Workiva Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
Expand Down
2 changes: 0 additions & 2 deletions lib/src/dom/accessibility_helpers.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// @dart = 2.7

// Copyright 2021 Workiva Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
Expand Down
3 changes: 1 addition & 2 deletions lib/src/dom/async/types.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// @dart = 2.7

// Copyright 2021 Workiva Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
Expand All @@ -25,6 +23,7 @@ import 'package:meta/meta.dart';
/// Returns either an `Error` or a `TestFailure` when provided with the [originalError].
typedef QueryTimeoutFn = /*Error || TestFailure*/ Object Function(/*Error*/ Object originalError);

// todo should all these be optional / nullable?
@JS()
@anonymous
class SharedJsWaitForOptions {
Expand Down
80 changes: 42 additions & 38 deletions lib/src/dom/async/wait_for.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// @dart = 2.7

// Copyright 2021 Workiva Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
Expand Down Expand Up @@ -56,48 +54,52 @@ export 'package:react_testing_library/src/dom/async/types.dart' show JsMutationO
/// {@category Async}
Future<T> waitFor<T>(
FutureOr<T> Function() expectation, {
Node container,
Duration timeout,
Node? container,
Duration? timeout,
Duration interval = const Duration(milliseconds: 50),
QueryTimeoutFn onTimeout,
QueryTimeoutFn? onTimeout,
MutationObserverOptions mutationObserverOptions = defaultMutationObserverOptions,
}) async {
final config = getConfig();
container ??= document.body;
container ??= document.body!;
timeout ??= Duration(milliseconds: config.asyncUtilTimeout);
onTimeout ??= (error) => error;

/*Error*/ dynamic lastError;
MutationObserver observer;
Timer intervalTimer;
Timer overallTimeoutTimer;
/*Error*/ Object? lastError;
late MutationObserver observer;
late Timer intervalTimer;
late Timer overallTimeoutTimer;
var isPending = false;
final doneCompleter = Completer<T>();

void onDone(Object error, T result) {
void onDone(T result) {
if (doneCompleter.isCompleted) return;

overallTimeoutTimer.cancel();
intervalTimer.cancel();
observer.disconnect();

if (error != null) {
doneCompleter.completeError(error);
} else if (result is TestFailure) {
if (result is TestFailure) {
doneCompleter.completeError(result);
} else {
doneCompleter.complete(result);
}
}

// Separate error handling to enforce non-nullability of the result.
void onDoneWithError(Object error) {
if (doneCompleter.isCompleted) return;

overallTimeoutTimer.cancel();
intervalTimer.cancel();
observer.disconnect();

doneCompleter.completeError(error);
}

void handleTimeout() {
/*Error*/ dynamic error;
if (lastError != null) {
error = lastError;
} else {
error = TimeoutException('Timed out in waitFor after ${timeout.inMilliseconds}ms.');
}
onDone(onTimeout(error), null);
final error = lastError ?? TimeoutException('Timed out in waitFor after ${timeout!.inMilliseconds}ms.');
onDoneWithError(onTimeout!(error));
}

void checkCallback() {
Expand All @@ -106,11 +108,11 @@ Future<T> waitFor<T>(
final result = expectation();
if (result is Future) {
isPending = true;
(result as Future)
.then((resolvedValue) => onDone(null, resolvedValue as T), onError: (e) => lastError = e)
(result! as Future)
.then((resolvedValue) => onDone(resolvedValue as T), onError: (e) => lastError = e)
aaronlademann-wf marked this conversation as resolved.
Show resolved Hide resolved
.whenComplete(() => isPending = false);
} else {
onDone(null, result as T);
onDone(result);
}
// If `callback` throws, wait for the next mutation, interval, or timeout.
} catch (error) {
Expand Down Expand Up @@ -159,20 +161,19 @@ Future<T> waitFor<T>(
/// {@category Async}
Future<void> waitForElementToBeRemoved(
Node Function() callback, {
Node container,
Duration timeout,
Node? container,
Duration? timeout,
Duration interval = const Duration(milliseconds: 50),
QueryTimeoutFn onTimeout,
QueryTimeoutFn? onTimeout,
MutationObserverOptions mutationObserverOptions = defaultMutationObserverOptions,
}) async {
final config = getConfig();
container ??= document.body;
container ??= document.body!;
timeout ??= Duration(milliseconds: config.asyncUtilTimeout);

final el = callback();
if (el == null) {
throw TestingLibraryElementError('The callback must return a non-null Element.');
}
// Keep null check to maintain backwards compatibility for consumers that are not opted in to null safety.
ArgumentError.checkNotNull(el);

if (!container.contains(el)) {
throw TestingLibraryElementError(
Expand All @@ -181,14 +182,14 @@ Future<void> waitForElementToBeRemoved(
}

await waitFor(
() => expect(container.contains(el), isFalse),
() => expect(container!.contains(el), isFalse),
container: container,
timeout: timeout,
interval: interval,
onTimeout: onTimeout ??
(error) {
return TimeoutException(
'The element returned from the callback was still present in the container after ${timeout.inMilliseconds}ms:\n\n'
'The element returned from the callback was still present in the container after ${timeout!.inMilliseconds}ms:\n\n'
'${prettyDOM(container)}');
},
mutationObserverOptions: mutationObserverOptions,
Expand Down Expand Up @@ -216,16 +217,19 @@ Future<void> waitForElementToBeRemoved(
/// {@category Async}
Future<void> waitForElementsToBeRemoved(
List<Node> Function() callback, {
Node container,
Duration timeout,
Node? container,
Duration? timeout,
Duration interval = const Duration(milliseconds: 50),
QueryTimeoutFn onTimeout,
QueryTimeoutFn? onTimeout,
MutationObserverOptions mutationObserverOptions = defaultMutationObserverOptions,
}) async {
container ??= document.body;
container ??= document.body!;
final els = callback();

if (els == null || els.isEmpty) {
// Keep null check to maintain backwards compatibility for consumers that are not opted in to null safety.
ArgumentError.checkNotNull(els);

if (els.isEmpty) {
throw TestingLibraryElementError('The callback must return one or more non-null Elements.');
}

Expand Down
22 changes: 10 additions & 12 deletions lib/src/dom/config/configure.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// @dart = 2.7

// Copyright 2021 Workiva Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
Expand Down Expand Up @@ -29,16 +27,16 @@ export 'package:react_testing_library/src/dom/config/types.dart' show JsConfig;
///
/// > See: <https://testing-library.com/docs/dom-testing-library/api-configuration/>
void configure({
String testIdAttribute,
int asyncUtilTimeout,
bool computedStyleSupportsPseudoElements,
bool defaultHidden,
bool showOriginalStackTrace,
bool throwSuggestions,
TestingLibraryElementError Function(Object message, Element container) getElementError,
String? testIdAttribute,
int? asyncUtilTimeout,
bool? computedStyleSupportsPseudoElements,
bool? defaultHidden,
bool? showOriginalStackTrace,
bool? throwSuggestions,
TestingLibraryElementError Function(Object? message, Element container)? getElementError,
}) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In a bunch of other unrelated type signatures - a param for Element container is nullable. Any reason why this is different?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's because it's non-nullable in TS. A lot of container related arguments are nullable because the default screen.container is set to document.body which is nullable. I talked to Greg about it though and he said it's safe to just enforce that document.body is non-null by the time it's used so then I can make all container args non-nullable instead so I'll update those

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Though now looking at that TS type, I'm not sure why message is typed as Object? instead of String? - do you happen to remember?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have no idea, honestly

JsError _getJsGetElementError(Object message, Element container) {
final dartError = allowInterop(getElementError)(message, container);
JsError _getJsGetElementError(Object? message, Element container) {
final dartError = allowInterop(getElementError!)(message ?? '', container);
return buildJsGetElementError(dartError.message, container);
}

Expand All @@ -55,7 +53,7 @@ void configure({
}

@JS('rtl.configure')
external void jsConfigure([JsConfig newConfig]);
external void jsConfigure([JsConfig? newConfig]);

/// Returns the configuration options being used by react-testing-library.
///
Expand Down
6 changes: 2 additions & 4 deletions lib/src/dom/config/types.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// @dart = 2.7

// Copyright 2021 Workiva Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
Expand Down Expand Up @@ -42,6 +40,6 @@ class JsConfig {
external bool get throwSuggestions;
external set throwSuggestions(bool value);

external /*JsError*/ dynamic Function(String message, Element container) get getElementError;
external set getElementError(/*JsError*/ dynamic Function(String message, Element container) value);
external /*JsError*/ dynamic Function(String? message, Element container) get getElementError;
external set getElementError(/*JsError*/ dynamic Function(String? message, Element container) value);
}
9 changes: 2 additions & 7 deletions lib/src/dom/fire_event.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// @dart = 2.7

// Copyright 2021 Workiva Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
Expand Down Expand Up @@ -125,8 +123,8 @@ external JsMap get _fireEventObj;
/// See: <https://testing-library.com/docs/dom-testing-library/api-events/#fireeventeventname>
///
/// {@category UserActions}
bool fireEventByName(String eventName, Element element, [Map eventProperties]) {
if (!JsBackedMap.fromJs(_jsEventMap).keys.contains(eventName)) {
bool fireEventByName(String eventName, Element element, [Map? eventProperties]) {
if (!JsBackedMap.fromJs(_fireEventObj).keys.contains(eventName)) {
throw ArgumentError.value(eventName, 'eventName');
}

Expand All @@ -139,6 +137,3 @@ bool fireEventByName(String eventName, Element element, [Map eventProperties]) {

return eventHandlerErrorCatcher(() => jsFireEventByNameFn(element, jsifyAndAllowInterop(eventProperties)));
}

@JS('rtl.eventMap')
external JsMap get _jsEventMap;
6 changes: 2 additions & 4 deletions lib/src/dom/matches/get_default_normalizer.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// @dart = 2.7

// Copyright 2021 Workiva Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
Expand All @@ -26,11 +24,11 @@ import 'package:react_testing_library/src/dom/matches/types.dart';
/// multiple adjacent whitespace characters into a single space.
///
/// > See: <https://testing-library.com/docs/queries/about#normalization>
NormalizerFn Function([NormalizerOptions]) getDefaultNormalizer([NormalizerOptions options]) {
NormalizerFn Function([NormalizerOptions?]) getDefaultNormalizer([NormalizerOptions? options]) {
return _jsGetDefaultNormalizer(NormalizerOptions()
..trim = options?.trim ?? true
..collapseWhitespace = options?.collapseWhitespace ?? true);
}

@JS('rtl.getDefaultNormalizer')
external NormalizerFn Function([NormalizerOptions]) _jsGetDefaultNormalizer([NormalizerOptions options]);
external NormalizerFn Function([NormalizerOptions?]) _jsGetDefaultNormalizer([NormalizerOptions? options]);
Loading
Loading