From ddc28d83384737f15ba08966da5754b5e06234bc Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Thu, 6 Nov 2025 07:11:24 -0800 Subject: [PATCH 1/4] Add typings for JSDate --- js_interop/lib/js_interop.dart | 5 + js_interop/lib/src/date.dart | 314 +++++++++++++++++++++++++++++++++ 2 files changed, 319 insertions(+) create mode 100644 js_interop/lib/js_interop.dart create mode 100644 js_interop/lib/src/date.dart diff --git a/js_interop/lib/js_interop.dart b/js_interop/lib/js_interop.dart new file mode 100644 index 00000000..06cbe1fa --- /dev/null +++ b/js_interop/lib/js_interop.dart @@ -0,0 +1,5 @@ +// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +export 'src/date.dart'; diff --git a/js_interop/lib/src/date.dart b/js_interop/lib/src/date.dart new file mode 100644 index 00000000..cb6364fe --- /dev/null +++ b/js_interop/lib/src/date.dart @@ -0,0 +1,314 @@ +// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:js_interop'; + +/// The JS [`Date`] type. +/// +/// [`Date`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date +@JS('Date') +extension type JSDate._(JSObject _) implements JSObject { + /// The [Date constructor] that returns the current date and time. + /// + /// [Date constructor]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/Date + external JSDate.now(); + + /// The [Date constructor] with the number of milliseconds since the epoch of + /// January 1, 1970, UTC. + /// + /// [Date constructor]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/Date#time_value_or_timestamp_number + external JSDate.fromMillisecondsSinceEpoch(int millisecondsSinceEpoch); + + /// The [Date constructor] that parses its value [from a string]. + /// + /// [Date constructor]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/Date + /// [from a string]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/Date#date_string + external JSDate.parse(String dateString); + + /// The [Date constructor] that copies its value [from an existing Date]. + /// + /// [Date constructor]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/Date + /// [from an existing Date]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/Date#date_object + external JSDate.from(JSDate other); + + /// The [Date constructor] that uses [individual component integers]. + /// + /// [Date constructor]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/Date + /// [individual component integers]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/Date#individual_date_and_time_component_values + external JSDate(int year, int month, + [int? day, int? hours, int? minutes, int? seconds, int? milliseconds]); + + /// Dee [`Date.now()`]. + /// + /// [`Date.now()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now + @JS('now') + external static int nowAsMillisecondsSinceEpoch(); + + /// See [`Date.parse()`]. + /// + /// [`Date.parse()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse + @JS('parse') + external static int parseAsMillisecondsSinceEpoch(String dateString); + + /// The [`Date.utc()`] function. + /// + /// [`Date.utc()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/UTC + @JS('UTC') + external static int utc(int year, + [int? month, + int? day, + int? hours, + int? minutes, + int? seconds, + int? milliseconds]); + + /// See [`Date.getDate()`] and [`Date.setDate()`]. + /// + /// [`Date.getDate()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getDate + /// [`Date.setDate()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/setDate + int get date => _getDate(); + set date(int value) => _setDate(value); + + @JS('getDate') + external int _getDate(); + + @JS('setDate') + external void _setDate(int value); + + /// See [`Date.getDay()`] and [`Date.setDay()`]. + /// + /// [`Date.getDay()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getDay + /// [`Date.setDay()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/setDay + int get day => _getDay(); + set day(int value) => _setDay(value); + + @JS('getDay') + external int _getDay(); + + @JS('setDay') + external void _setDay(int value); + + /// See [`Date.getFullYear()`] and [`Date.setFullYear()`]. + /// + /// [`Date.getFullYear()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getFullYear + /// [`Date.setFullYear()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/setFullYear + int get fullYear => _getFullYear(); + set fullYear(int value) => _setFullYear(value); + + @JS('getFullYear') + external int _getFullYear(); + + @JS('setFullYear') + external void _setFullYear(int value); + + /// See [`Date.getHours()`] and [`Date.setHours()`]. + /// + /// [`Date.getHours()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getHours + /// [`Date.setHours()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/setHours + int get hours => _getHours(); + set hours(int value) => _setHours(value); + + @JS('getHours') + external int _getHours(); + + @JS('setHours') + external void _setHours(int value); + + /// See [`Date.getMilliseconds()`] and [`Date.setMilliseconds()`]. + /// + /// [`Date.getMilliseconds()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getMilliseconds + /// [`Date.setMilliseconds()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/setMilliseconds + int get milliseconds => _getMilliseconds(); + set milliseconds(int value) => _setMilliseconds(value); + + @JS('getMilliseconds') + external int _getMilliseconds(); + + @JS('setMilliseconds') + external void _setMilliseconds(int value); + + /// See [`Date.getMinutes()`] and [`Date.setMinutes()`]. + /// + /// [`Date.getMinutes()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getMinutes + /// [`Date.setMinutes()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/setMinutes + int get minutes => _getMinutes(); + set minutes(int value) => _setMinutes(value); + + @JS('getMinutes') + external int _getMinutes(); + + @JS('setMinutes') + external void _setMinutes(int value); + + /// See [`Date.getMonth()`] and [`Date.setMonth()`]. + /// + /// [`Date.getMonth()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getMonth + /// [`Date.setMonth()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/setMonth + int get month => _getMonth(); + set month(int value) => _setMonth(value); + + @JS('getMonth') + external int _getMonth(); + + @JS('setMonth') + external void _setMonth(int value); + + /// See [`Date.getSeconds()`] and [`Date.setSeconds()`]. + /// + /// [`Date.getSeconds()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getSeconds + /// [`Date.setSeconds()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/setSeconds + int get seconds => _getSeconds(); + set seconds(int value) => _setSeconds(value); + + @JS('getSeconds') + external int _getSeconds(); + + @JS('setSeconds') + external void _setSeconds(int value); + + /// See [`Date.getTime()`] and [`Date.setTime()`]. + /// + /// [`Date.getTime()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getTime + /// [`Date.setTime()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/setTime + int get time => _getTime(); + set time(int value) => _setTime(value); + + @JS('getTime') + external int _getTime(); + + @JS('setTime') + external void _setTime(int value); + + /// See [`Date.getTimezoneOffset()`]. + /// + /// [`Date.getTimezoneOffset()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getTimezoneOffset + int get timezoneOffset => _getTimezoneOffset(); + + @JS('getTimezoneOffset') + external int _getTimezoneOffset(); + + /// See [`Date.getUTCDate()`] and [`Date.setUTCDate()`]. + /// + /// [`Date.getUTCDate()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getUTCDate + /// [`Date.setUTCDate()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/setUTCDate + int get utcDate => _getUtcDate(); + set utcDate(int value) => _setUtcDate(value); + + @JS('getUTCDate') + external int _getUtcDate(); + + @JS('setUTCDate') + external void _setUtcDate(int value); + + /// See [`Date.getUTCFullYear()`] and [`Date.setUTCFullYear()`]. + /// + /// [`Date.getUTCFullYear()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getUTCFullYear + /// [`Date.setUTCFullYear()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/setUTCFullYear + int get utcFullYear => _getUtcFullYear(); + set utcFullYear(int value) => _setUtcFullYear(value); + + @JS('getUTCFullYear') + external int _getUtcFullYear(); + + @JS('setUTCFullYear') + external void _setUtcFullYear(int value); + + /// See [`Date.getUTCHours()`] and [`Date.setUTCHours()`]. + /// + /// [`Date.getUTCHours()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getUTCHours + /// [`Date.setUTCHours()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/setUTCHours + int get utcHours => _getUtcHours(); + set utcHours(int value) => _setUtcHours(value); + + @JS('getUTCHours') + external int _getUtcHours(); + + @JS('setUTCHours') + external void _setUtcHours(int value); + + /// See [`Date.getUTCMilliseconds()`] and [`Date.setUTCMilliseconds()`]. + /// + /// [`Date.getUTCMilliseconds()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getUTCMilliseconds + /// [`Date.setUTCMilliseconds()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/setUTCMilliseconds + int get utcMilliseconds => _getUtcMilliseconds(); + set utcMilliseconds(int value) => _setUtcMilliseconds(value); + + @JS('getUTCMilliseconds') + external int _getUtcMilliseconds(); + + @JS('setUTCMilliseconds') + external void _setUtcMilliseconds(int value); + + /// See [`Date.getUTCMinutes()`] and [`Date.setUTCMinutes()`]. + /// + /// [`Date.getUTCMinutes()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getUTCMinutes + /// [`Date.setUTCMinutes()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/setUTCMinutes + int get utcMinutes => _getUtcMinutes(); + set utcMinutes(int value) => _setUtcMinutes(value); + + @JS('getUTCMinutes') + external int _getUtcMinutes(); + + @JS('setUTCMinutes') + external void _setUtcMinutes(int value); + + /// See [`Date.getUTCMonth()`] and [`Date.setUTCMonth()`]. + /// + /// [`Date.getUTCMonth()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getUTCMonth + /// [`Date.setUTCMonth()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/setUTCMonth + int get utcMonth => _getUtcMonth(); + set utcMonth(int value) => _setUtcMonth(value); + + @JS('getUTCMonth') + external int _getUtcMonth(); + + @JS('setUTCMonth') + external void _setUtcMonth(int value); + + /// See [`Date.getUTCSeconds()`] and [`Date.setUTCSeconds()`]. + /// + /// [`Date.getUTCSeconds()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getUTCSeconds + /// [`Date.setUTCSeconds()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/setUTCSeconds + int get utcSeconds => _getUtcSeconds(); + set utcSeconds(int value) => _setUtcSeconds(value); + + @JS('getUTCSeconds') + external int _getUtcSeconds(); + + @JS('setUTCSeconds') + external void _setUtcSeconds(int value); + + /// See [`Date.toDateString()`]. + /// + /// [`Date.toDateString()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toDateString + external String toDateString(); + + /// See [`Date.toDateString()`]. + /// + /// [`Date.toDateString()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toDateString + @JS('toISOString') + external String toIsoString(); + + // TODO - Add `toLocale*String` when Intl.DateTimeFormat is fully typed. + + /// See [`Date.toTimeString()`]. + /// + /// [`Date.toTimeString()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toTimeString + external String toTimeString(); + + /// See [`Date.toUTCString()`]. + /// + /// [`Date.toUTCString()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toUTCString + @JS('toUTCString') + external String toUtcString(); + + /// Converts this to a Dart [DateTime] that represents the same point in time + /// in the local time zone. + DateTime get toDart => DateTime.fromMillisecondsSinceEpoch(time); + + /// Converts this to a Dart [DateTime] that represents the same point in time + /// in the UTC time zone. + DateTime get toDartUtc => + DateTime.fromMillisecondsSinceEpoch(time, isUtc: true); +} From 8955e52f299c0a3f126672a9a917fd84ceb8755c Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Tue, 11 Nov 2025 12:25:52 -0800 Subject: [PATCH 2/4] Regularize member names --- js_interop/lib/src/date.dart | 93 +++++++++++++++++++++++++++++------- 1 file changed, 77 insertions(+), 16 deletions(-) diff --git a/js_interop/lib/src/date.dart b/js_interop/lib/src/date.dart index cb6364fe..00d6de7d 100644 --- a/js_interop/lib/src/date.dart +++ b/js_interop/lib/src/date.dart @@ -12,7 +12,7 @@ extension type JSDate._(JSObject _) implements JSObject { /// The [Date constructor] that returns the current date and time. /// /// [Date constructor]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/Date - external JSDate.now(); + external JSDate.nowAsDate(); /// The [Date constructor] with the number of milliseconds since the epoch of /// January 1, 1970, UTC. @@ -24,7 +24,7 @@ extension type JSDate._(JSObject _) implements JSObject { /// /// [Date constructor]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/Date /// [from a string]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/Date#date_string - external JSDate.parse(String dateString); + external JSDate.parseAsDate(String dateString); /// The [Date constructor] that copies its value [from an existing Date]. /// @@ -32,12 +32,75 @@ extension type JSDate._(JSObject _) implements JSObject { /// [from an existing Date]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/Date#date_object external JSDate.from(JSDate other); - /// The [Date constructor] that uses [individual component integers]. + /// The [Date constructor] that uses [individual component integers], + /// interpreted in the local time zone. /// /// [Date constructor]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/Date /// [individual component integers]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/Date#individual_date_and_time_component_values - external JSDate(int year, int month, - [int? day, int? hours, int? minutes, int? seconds, int? milliseconds]); + external JSDate.localDate( + int year, + int month, [ + int? day, + int? hours, + int? minutes, + int? seconds, + int? milliseconds, + ]); + + /// The [Date constructor] that uses [individual component integers], + /// interpreted in the UTC time zone. + /// + /// [Date constructor]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/Date + /// [individual component integers]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/Date#individual_date_and_time_component_values + factory JSDate.utcDate( + int year, + int month, [ + int? day, + int? hours, + int? minutes, + int? seconds, + int? milliseconds, + ]) { + var ms = switch ((day, hours, minutes, seconds, milliseconds)) { + (_, _, _, _, var milliseconds?) => JSDate.utcAsMillisecondsSinceEpoch( + year, + month, + day, + hours, + minutes, + seconds, + milliseconds, + ), + (_, _, _, var seconds?, _) => JSDate.utcAsMillisecondsSinceEpoch( + year, + month, + day, + hours, + minutes, + seconds, + ), + (_, _, var minutes?, _, _) => JSDate.utcAsMillisecondsSinceEpoch( + year, + month, + day, + hours, + minutes, + ), + (_, var hours?, _, _, _) => JSDate.utcAsMillisecondsSinceEpoch( + year, + month, + day, + hours, + ), + (var day?, _, _, _, _) => JSDate.utcAsMillisecondsSinceEpoch( + year, + month, + day, + ), + _ => JSDate.utcAsMillisecondsSinceEpoch(year, month), + }; + return JSDate.fromMillisecondsSinceEpoch(ms); + } /// Dee [`Date.now()`]. /// @@ -55,13 +118,15 @@ extension type JSDate._(JSObject _) implements JSObject { /// /// [`Date.utc()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/UTC @JS('UTC') - external static int utc(int year, - [int? month, - int? day, - int? hours, - int? minutes, - int? seconds, - int? milliseconds]); + external static int utcAsMillisecondsSinceEpoch( + int year, [ + int? month, + int? day, + int? hours, + int? minutes, + int? seconds, + int? milliseconds, + ]); /// See [`Date.getDate()`] and [`Date.setDate()`]. /// @@ -81,14 +146,10 @@ extension type JSDate._(JSObject _) implements JSObject { /// [`Date.getDay()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getDay /// [`Date.setDay()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/setDay int get day => _getDay(); - set day(int value) => _setDay(value); @JS('getDay') external int _getDay(); - @JS('setDay') - external void _setDay(int value); - /// See [`Date.getFullYear()`] and [`Date.setFullYear()`]. /// /// [`Date.getFullYear()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getFullYear From 787b64cfa57394df1b3fb9b0657e5040a09ade54 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Tue, 11 Nov 2025 12:27:39 -0800 Subject: [PATCH 3/4] Add DateTimeToJSDate --- js_interop/lib/js_interop.dart | 1 + js_interop/lib/src/dart/date_time.dart | 10 ++++++++++ 2 files changed, 11 insertions(+) create mode 100644 js_interop/lib/src/dart/date_time.dart diff --git a/js_interop/lib/js_interop.dart b/js_interop/lib/js_interop.dart index 06cbe1fa..2426b8e9 100644 --- a/js_interop/lib/js_interop.dart +++ b/js_interop/lib/js_interop.dart @@ -2,4 +2,5 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +export 'src/dart/date_time.dart'; export 'src/date.dart'; diff --git a/js_interop/lib/src/dart/date_time.dart b/js_interop/lib/src/dart/date_time.dart new file mode 100644 index 00000000..7b866293 --- /dev/null +++ b/js_interop/lib/src/dart/date_time.dart @@ -0,0 +1,10 @@ +// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../date.dart'; + +extension DateTimeToJSDate on DateTime { + /// Converts this to a [JSDate] that represents the same instant in time. + JSDate get toJS => JSDate.fromMillisecondsSinceEpoch(millisecondsSinceEpoch); +} From d13f65501b5328508dc7e01854744b727bc9573f Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Tue, 11 Nov 2025 12:27:50 -0800 Subject: [PATCH 4/4] Add Date tests --- .github/workflows/js_interop.yaml | 41 ++++++ js_interop/dart_test.yaml | 1 + js_interop/pubspec.yaml | 3 + js_interop/test/date_test.dart | 212 ++++++++++++++++++++++++++++++ 4 files changed, 257 insertions(+) create mode 100644 .github/workflows/js_interop.yaml create mode 100644 js_interop/dart_test.yaml create mode 100644 js_interop/test/date_test.dart diff --git a/.github/workflows/js_interop.yaml b/.github/workflows/js_interop.yaml new file mode 100644 index 00000000..f131f6bf --- /dev/null +++ b/.github/workflows/js_interop.yaml @@ -0,0 +1,41 @@ +name: package:js_interop +permissions: read-all + +on: + # Run CI on pushes to the main branch and on PRs. + push: + branches: [ main ] + paths: + - '.github/workflows/js_interop.yaml' + - 'js_interop/**' + pull_request: + paths: + - '.github/workflows/js_interop.yaml' + - 'js_interop/**' + schedule: + - cron: "0 0 * * 0" + +defaults: + run: + working-directory: js_interop/ + +jobs: + build: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + sdk: [3.9, beta, dev] + test_config: ['-p chrome', '-p chrome -c dart2wasm', '-p node'] + + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 + - uses: dart-lang/setup-dart@e51d8e571e22473a2ddebf0ef8a2123f0ab2c02c + with: + sdk: ${{ matrix.sdk }} + + - run: dart pub get + - run: dart format --output=none --set-exit-if-changed . + if: ${{ matrix.sdk == 'dev' }} + - run: dart analyze --fatal-infos + - run: dart test ${{ matrix.test_config }} diff --git a/js_interop/dart_test.yaml b/js_interop/dart_test.yaml new file mode 100644 index 00000000..7b2665b3 --- /dev/null +++ b/js_interop/dart_test.yaml @@ -0,0 +1 @@ +platforms: [chrome, node] diff --git a/js_interop/pubspec.yaml b/js_interop/pubspec.yaml index 8207a36e..3cc5e9a0 100644 --- a/js_interop/pubspec.yaml +++ b/js_interop/pubspec.yaml @@ -5,3 +5,6 @@ repository: https://github.com/dart-lang/web environment: sdk: ^3.9.0 + +dev_dependencies: + test: ^1.26.0 diff --git a/js_interop/test/date_test.dart b/js_interop/test/date_test.dart new file mode 100644 index 00000000..76b334be --- /dev/null +++ b/js_interop/test/date_test.dart @@ -0,0 +1,212 @@ +// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file.p + +import 'dart:js_interop'; + +import 'package:test/test.dart'; + +import 'package:js_interop/js_interop.dart'; + +final Matcher _isDate = predicate( + (jsDate) => jsDate is JSObject && jsDate.isA(), + "is a JSDate", +); + +void main() { + group('constructors', () { + test('nowAsDate', () => expect(JSDate.nowAsDate(), _isDate)); + + test( + 'fromMillisecondsSinceEpoch', + () => expect(JSDate.fromMillisecondsSinceEpoch(1234567890), _isDate), + ); + + test( + 'parseAsDate', + () => expect(JSDate.parseAsDate("11 Nov 2025"), _isDate), + ); + + test('from', () => expect(JSDate.from(JSDate.nowAsDate()), _isDate)); + + group('localDate', () { + test( + 'with no optional args', + () => expect(JSDate.localDate(2025, 11), _isDate), + ); + + test( + 'with all optional args', + () => expect(JSDate.localDate(2025, 11, 11, 12, 2, 15, 120), _isDate), + ); + }); + + group('utcDate', () { + test( + 'with no optional args', + () => expect(JSDate.utcDate(2025, 11), _isDate), + ); + + test( + 'with one optional arg', + () => expect(JSDate.utcDate(2025, 11, 11), _isDate), + ); + + test( + 'with two optional args', + () => expect(JSDate.utcDate(2025, 11, 11, 12), _isDate), + ); + + test( + 'with three optional args', + () => expect(JSDate.utcDate(2025, 11, 11, 12, 2), _isDate), + ); + + test( + 'with four optional arg', + () => expect(JSDate.utcDate(2025, 11, 11, 12, 2, 15), _isDate), + ); + + test( + 'with all optional args', + () => expect(JSDate.utcDate(2025, 11, 11, 12, 2, 15, 120), _isDate), + ); + }); + }); + + group('static', () { + test( + 'nowAsMillisecondsSinceEpoch', + () => expect(JSDate.nowAsMillisecondsSinceEpoch(), isA()), + ); + + test( + 'parseAsMillisecondsSinceEpoch', + () => expect( + JSDate.parseAsMillisecondsSinceEpoch("11 Nov 2025"), + isA(), + ), + ); + + group('utcAsMillisecondsSinceEpoch', () { + test( + 'with no optional args', + () => expect(JSDate.utcAsMillisecondsSinceEpoch(2025, 11), isA()), + ); + + test( + 'with all optional args', + () => expect( + JSDate.utcAsMillisecondsSinceEpoch(2025, 11, 11, 12, 2, 15, 120), + isA(), + ), + ); + }); + }); + + group('instance', () { + late JSDate date; + setUp(() => date = JSDate.nowAsDate()); + + test('date', () { + date.date = 12; + expect(date.date, equals(12)); + }); + + test('day', () => expect(date.day, isA())); + + test('fullYear', () { + date.fullYear = 2026; + expect(date.fullYear, equals(2026)); + }); + + test('hours', () { + date.hours = 13; + expect(date.hours, equals(13)); + }); + + test('milliseconds', () { + date.milliseconds = 123; + expect(date.milliseconds, equals(123)); + }); + + test('minutes', () { + date.minutes = 5; + expect(date.minutes, equals(5)); + }); + + test('month', () { + date.month = 1; + expect(date.month, equals(1)); + }); + + test('seconds', () { + date.seconds = 5; + expect(date.seconds, equals(5)); + }); + + test('time', () { + date.time = 1234567890; + expect(date.time, equals(1234567890)); + }); + + test('timezoneOffset', () => expect(date.timezoneOffset, isA())); + + test('utcDate', () { + date.utcDate = 12; + expect(date.utcDate, equals(12)); + }); + + test('utcFullYear', () { + date.utcFullYear = 2026; + expect(date.utcFullYear, equals(2026)); + }); + + test('utcHours', () { + date.utcHours = 13; + expect(date.utcHours, equals(13)); + }); + + test('utcMilliseconds', () { + date.utcMilliseconds = 123; + expect(date.utcMilliseconds, equals(123)); + }); + + test('utcMinutes', () { + date.utcMinutes = 5; + expect(date.utcMinutes, equals(5)); + }); + + test('utcMonth', () { + date.utcMonth = 1; + expect(date.utcMonth, equals(1)); + }); + + test('utcSeconds', () { + date.utcSeconds = 5; + expect(date.utcSeconds, equals(5)); + }); + + test('toDateString', () => expect(date.toDateString(), isA())); + + test('toIsoString:', () => expect(date.toIsoString(), isA())); + + test('toTimeString:', () => expect(date.toTimeString(), isA())); + + test('toUtcString:', () => expect(date.toUtcString(), isA())); + + test('toDart', () { + var dartDate = date.toDart; + expect(dartDate, isA()); + expect(dartDate.timeZoneName, equals(DateTime.now().timeZoneName)); + }); + + test('toDartUtc', () { + var dartDate = date.toDartUtc; + expect(dartDate, isA()); + expect(dartDate.timeZoneName, equals("UTC")); + }); + + test('from Dart', () => expect(DateTime.now().toJS, _isDate)); + }); +}