summaryrefslogtreecommitdiffstats
path: root/js/src/tests/test262/built-ins/Temporal/Calendar/prototype
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /js/src/tests/test262/built-ins/Temporal/Calendar/prototype
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/src/tests/test262/built-ins/Temporal/Calendar/prototype')
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/browser.js0
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/constructor.js20
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/add-days.js39
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/add-months-weeks.js39
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/add-months.js36
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/add-weeks-days.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/add-weeks.js66
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/add-years-months-days.js48
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/add-years-months.js30
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/add-years-weeks.js33
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/add-years.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-builtin-calendar-no-array-iteration.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-calendar-datefromfields-called-with-null-prototype-fields.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-constructor-in-calendar-fields.js17
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-duplicate-calendar-fields.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-duration-max.js58
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-duration-out-of-range.js75
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-duration-years-and-months-number-max-value.js38
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-leap-second.js30
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-number.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-plaindatetime.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-propertybag-calendar-case-insensitive.js20
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-propertybag-calendar-leap-second.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-propertybag-calendar-number.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-propertybag-calendar-string.js20
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-propertybag-calendar-wrong-type.js46
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-propertybag-calendar-year-zero.js27
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-proto-in-calendar-fields.js17
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-calendar-annotation.js34
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-critical-unknown-annotation.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-date-with-utc-offset.js49
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-invalid.js64
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-multiple-calendar.js32
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-multiple-time-zone.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-time-separators.js30
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-time-zone-annotation.js39
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-unknown-annotation.js33
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-with-utc-designator.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-wrong-type.js43
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-convert.js22
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-slots.js40
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js20
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js20
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/balance-smaller-units.js25
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/basic.js53
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/branding.js27
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/browser.js0
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/builtin.js36
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/calendar-datefromfields-called-with-options-undefined.js18
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/calendar-fields-iterable.js36
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/calendar-temporal-object.js30
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/date-infinity-throws-rangeerror.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/duration-argument-string-negative-fractional-units.js21
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/length.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/name.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/not-a-constructor.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/options-object.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/options-wrong-type.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/order-of-operations.js122
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/overflow-invalid-string.js30
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/overflow-undefined.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/overflow-wrong-type.js27
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/prop-desc.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/shell.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/throw-range-error-from-ToTemporalDate.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/throw-range-error-from-ToTemporalDuration.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/throw-type-error-from-GetOptionsObject.js23
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/year-zero.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/branding.js27
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/browser.js0
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/builtin.js36
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/fields-not-object.js23
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/infinity-throws-rangeerror.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/length.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/missing-properties.js48
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/name.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/not-a-constructor.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/one-of-era-erayear-undefined.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/options-object.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/options-wrong-type.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/order-of-operations.js49
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/overflow-invalid-string.js31
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/overflow-undefined.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/overflow-wrong-type.js27
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/prop-desc.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/shell.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/throw-type-error-from-GetOptionsObject.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/throws-range-error.js126
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/throws-type-error.js58
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/with-year-month-day-need-constrain.js90
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/with-year-month-day.js25
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/with-year-monthCode-day-need-constrain.js80
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/with-year-monthCode-day.js25
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-builtin-calendar-no-array-iteration.js25
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-calendar-datefromfields-called-with-null-prototype-fields.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-constructor-in-calendar-fields.js17
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-duplicate-calendar-fields.js20
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-infinity-throws-rangeerror.js34
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-number.js33
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-plaindatetime.js33
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-propertybag-calendar-case-insensitive.js22
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-propertybag-calendar-leap-second.js22
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-propertybag-calendar-number.js34
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-propertybag-calendar-string.js31
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-propertybag-calendar-wrong-type.js52
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-propertybag-calendar-year-zero.js32
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-proto-in-calendar-fields.js17
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-string-calendar-annotation.js34
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-string-critical-unknown-annotation.js33
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-string-date-with-utc-offset.js52
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-string-invalid.js70
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-string-multiple-calendar.js37
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-string-multiple-time-zone.js33
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-string-time-separators.js35
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-string-time-zone-annotation.js39
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-string-unknown-annotation.js33
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-string-with-utc-designator.js30
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-wrong-type.js50
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-zoneddatetime-slots.js41
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js22
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js30
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js22
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js31
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/basic.js48
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/branding.js27
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/browser.js0
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/builtin.js36
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/calendar-datefromfields-called-with-options-undefined.js18
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/calendar-fields-iterable.js43
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/calendar-temporal-object.js33
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/largest-unit-day.js62
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/largest-unit-month.js97
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/largest-unit-week.js74
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/largest-unit-year.js207
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/largestunit-plurals-accepted.js23
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/leap-second.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/length.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/name.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/no-options.js59
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/not-a-constructor.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/options-object.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/options-wrong-type.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/order-of-operations.js129
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/prop-desc.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/shell.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/throws-range-error-ToLargestTemporalUnit.js20
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/throws-range-error-ToTemporalDate.js21
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/throws-type-error-GetOptionsObject.js21
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/year-zero.js34
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-builtin-calendar-no-array-iteration.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-calendar-datefromfields-called-with-null-prototype-fields.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-constructor-in-calendar-fields.js17
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-duplicate-calendar-fields.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-leap-second.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-number.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-propertybag-calendar-case-insensitive.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-propertybag-calendar-leap-second.js23
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-propertybag-calendar-number.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-propertybag-calendar-string.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-propertybag-calendar-wrong-type.js46
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-propertybag-calendar-year-zero.js27
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-proto-in-calendar-fields.js17
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-string-calendar-annotation.js33
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-string-critical-unknown-annotation.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-string-date-with-utc-offset.js48
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-string-invalid.js64
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-string-multiple-calendar.js32
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-string-multiple-time-zone.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-string-time-separators.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-string-time-zone-annotation.js38
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-string-unknown-annotation.js32
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-string-with-utc-designator.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-wrong-type.js43
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-zoneddatetime-convert.js22
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-zoneddatetime-slots.js40
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js23
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/basic.js20
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/branding.js27
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/browser.js0
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/builtin.js36
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/calendar-datefromfields-called-with-options-undefined.js18
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/calendar-fields-iterable.js37
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/calendar-temporal-object.js31
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/date-time.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/date.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/infinity-throws-rangeerror.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/length.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/month-day.js23
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/name.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/not-a-constructor.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/prop-desc.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/shell.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/string.js22
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/throw-range-error-ToTemporalDate.js22
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/year-zero.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-builtin-calendar-no-array-iteration.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-calendar-datefromfields-called-with-null-prototype-fields.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-constructor-in-calendar-fields.js17
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-duplicate-calendar-fields.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-leap-second.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-number.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-propertybag-calendar-case-insensitive.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-propertybag-calendar-leap-second.js23
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-propertybag-calendar-number.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-propertybag-calendar-string.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-propertybag-calendar-wrong-type.js46
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-propertybag-calendar-year-zero.js27
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-proto-in-calendar-fields.js17
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-string-calendar-annotation.js33
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-string-critical-unknown-annotation.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-string-date-with-utc-offset.js48
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-string-invalid.js64
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-string-multiple-calendar.js32
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-string-multiple-time-zone.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-string-time-separators.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-string-time-zone-annotation.js38
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-string-unknown-annotation.js32
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-string-with-utc-designator.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-wrong-type.js43
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-zoneddatetime-convert.js22
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-zoneddatetime-slots.js40
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js23
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/basic.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/branding.js27
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/browser.js0
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/builtin.js36
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/calendar-datefromfields-called-with-options-undefined.js18
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/calendar-fields-iterable.js35
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/calendar-temporal-object.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/infinity-throws-rangeerror.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/length.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/name.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/not-a-constructor.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/plain-date-time.js40
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/plain-date.js22
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/prop-desc.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/shell.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/string.js21
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/throw-range-error-ToTemporalDate.js18
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/year-zero.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-builtin-calendar-no-array-iteration.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-calendar-datefromfields-called-with-null-prototype-fields.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-constructor-in-calendar-fields.js17
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-duplicate-calendar-fields.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-leap-second.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-number.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-propertybag-calendar-case-insensitive.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-propertybag-calendar-leap-second.js23
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-propertybag-calendar-number.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-propertybag-calendar-string.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-propertybag-calendar-wrong-type.js46
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-propertybag-calendar-year-zero.js27
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-proto-in-calendar-fields.js17
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-string-calendar-annotation.js33
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-string-critical-unknown-annotation.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-string-date-with-utc-offset.js48
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-string-invalid.js64
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-string-multiple-calendar.js32
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-string-multiple-time-zone.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-string-time-separators.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-string-time-zone-annotation.js38
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-string-unknown-annotation.js32
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-string-with-utc-designator.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-wrong-type.js43
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-zoneddatetime-convert.js22
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-zoneddatetime-slots.js40
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js23
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/basic.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/branding.js27
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/browser.js0
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/builtin.js36
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/calendar-datefromfields-called-with-options-undefined.js18
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/calendar-fields-iterable.js35
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/calendar-temporal-object.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/infinity-throws-rangeerror.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/length.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/name.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/not-a-constructor.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/plain-date-time.js58
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/plain-date.js41
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/prop-desc.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/shell.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/string.js37
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/throw-range-error-ToTemporalDate.js18
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/year-zero.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-builtin-calendar-no-array-iteration.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-calendar-datefromfields-called-with-null-prototype-fields.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-constructor-in-calendar-fields.js17
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-duplicate-calendar-fields.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-leap-second.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-number.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-propertybag-calendar-case-insensitive.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-propertybag-calendar-leap-second.js23
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-propertybag-calendar-number.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-propertybag-calendar-string.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-propertybag-calendar-wrong-type.js46
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-propertybag-calendar-year-zero.js27
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-proto-in-calendar-fields.js17
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-calendar-annotation.js33
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-critical-unknown-annotation.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-date-with-utc-offset.js48
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-invalid.js64
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-multiple-calendar.js32
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-multiple-time-zone.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-time-separators.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-time-zone-annotation.js38
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-unknown-annotation.js32
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-with-utc-designator.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-wrong-type.js43
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-convert.js22
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-slots.js40
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js23
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/basic.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/branding.js27
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/browser.js0
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/builtin.js36
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/calendar-datefromfields-called-with-options-undefined.js18
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/calendar-fields-iterable.js35
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/calendar-temporal-object.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/infinity-throws-rangeerror.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/length.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/name.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/not-a-constructor.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/plain-date-time.js116
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/plain-date.js58
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/prop-desc.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/shell.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/string.js35
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/throw-range-error-ToTemporalDate.js21
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/year-zero.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-builtin-calendar-no-array-iteration.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-calendar-datefromfields-called-with-null-prototype-fields.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-constructor-in-calendar-fields.js17
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-duplicate-calendar-fields.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-leap-second.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-number.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-propertybag-calendar-case-insensitive.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-propertybag-calendar-leap-second.js23
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-propertybag-calendar-number.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-propertybag-calendar-string.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-propertybag-calendar-wrong-type.js46
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-propertybag-calendar-year-zero.js27
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-proto-in-calendar-fields.js17
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-string-calendar-annotation.js33
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-string-critical-unknown-annotation.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-string-date-with-utc-offset.js48
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-string-invalid.js64
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-string-multiple-calendar.js32
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-string-multiple-time-zone.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-string-time-separators.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-string-time-zone-annotation.js38
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-string-unknown-annotation.js32
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-string-with-utc-designator.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-wrong-type.js43
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-zoneddatetime-convert.js22
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-zoneddatetime-slots.js40
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js23
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/basic.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/branding.js27
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/browser.js0
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/builtin.js36
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/calendar-datefromfields-called-with-options-undefined.js18
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/calendar-fields-iterable.js35
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/calendar-temporal-object.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/date-time.js21
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/date.js16
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/infinity-throws-rangeerror.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/length.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/name.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/not-a-constructor.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/prop-desc.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/shell.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/string.js17
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/throw-range-error-ToTemporalDate.js18
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/year-zero.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-builtin-calendar-no-array-iteration.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-calendar-datefromfields-called-with-null-prototype-fields.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-constructor-in-calendar-fields.js17
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-duplicate-calendar-fields.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-leap-second.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-number.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-propertybag-calendar-case-insensitive.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-propertybag-calendar-leap-second.js23
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-propertybag-calendar-number.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-propertybag-calendar-string.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-propertybag-calendar-wrong-type.js46
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-propertybag-calendar-year-zero.js27
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-proto-in-calendar-fields.js17
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-string-calendar-annotation.js33
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-string-critical-unknown-annotation.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-string-date-with-utc-offset.js48
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-string-invalid.js64
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-string-multiple-calendar.js32
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-string-multiple-time-zone.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-string-time-separators.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-string-time-zone-annotation.js38
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-string-unknown-annotation.js32
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-string-with-utc-designator.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-wrong-type.js43
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-zoneddatetime-convert.js22
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-zoneddatetime-slots.js40
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js23
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/basic.js20
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/branding.js27
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/browser.js0
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/builtin.js36
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/calendar-datefromfields-called-with-options-undefined.js18
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/calendar-fields-iterable.js37
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/calendar-temporal-object.js31
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/infinity-throws-rangeerror.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/length.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/name.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/not-a-constructor.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/plain-date-time.js94
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/plain-date.js48
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/prop-desc.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/shell.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/string.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/throw-range-error-ToTemporalDate.js21
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/year-zero.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/argument-iterable-not-array.js30
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/argument-throws-duplicate-keys.js31
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/argument-throws-invalid-keys.js46
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/branding.js27
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/browser.js0
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/builtin.js36
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/length.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/long-input.js50
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/name.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/non-string-element-throws.js20
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/not-a-constructor.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/prop-desc.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/repeated-throw.js58
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/reverse.js39
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/shell.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/id/branding.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/id/browser.js0
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/id/custom-calendar.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/id/prop-desc.js17
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/id/shell.js0
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-builtin-calendar-no-array-iteration.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-calendar-datefromfields-called-with-null-prototype-fields.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-constructor-in-calendar-fields.js17
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-duplicate-calendar-fields.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-leap-second.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-number.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-propertybag-calendar-case-insensitive.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-propertybag-calendar-leap-second.js23
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-propertybag-calendar-number.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-propertybag-calendar-string.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-propertybag-calendar-wrong-type.js46
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-propertybag-calendar-year-zero.js27
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-proto-in-calendar-fields.js17
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string-calendar-annotation.js33
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string-critical-unknown-annotation.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string-date-with-utc-offset.js48
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string-invalid.js64
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string-multiple-calendar.js32
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string-multiple-time-zone.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string-time-separators.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string-time-zone-annotation.js38
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string-unknown-annotation.js32
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string-with-utc-designator.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-wrong-type.js43
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-zoneddatetime-convert.js22
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-zoneddatetime-slots.js40
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js23
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/basic.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/branding.js27
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/browser.js0
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/builtin.js36
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/calendar-datefromfields-called-with-options-undefined.js18
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/calendar-fields-iterable.js37
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/calendar-temporal-object.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/infinity-throws-rangeerror.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/length.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/name.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/not-a-constructor.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/prop-desc.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/shell.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/year-zero.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/arguments-empty-object.js35
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/arguments-not-object.js43
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/basic.js36
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/branding.js27
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/browser.js0
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/builtin.js36
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/iso8601-calendar-month-monthCode.js102
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/length.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/name.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/non-string-properties.js58
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/not-a-constructor.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/order-of-operations.js50
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/prop-desc.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/shell.js353
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-builtin-calendar-no-array-iteration.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-calendar-datefromfields-called-with-null-prototype-fields.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-constructor-in-calendar-fields.js17
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-duplicate-calendar-fields.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-leap-second.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-number.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-propertybag-calendar-case-insensitive.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-propertybag-calendar-leap-second.js23
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-propertybag-calendar-number.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-propertybag-calendar-string.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-propertybag-calendar-wrong-type.js46
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-propertybag-calendar-year-zero.js27
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-proto-in-calendar-fields.js17
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-string-calendar-annotation.js33
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-string-critical-unknown-annotation.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-string-date-with-utc-offset.js48
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-string-invalid.js64
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-string-multiple-calendar.js32
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-string-multiple-time-zone.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-string-time-separators.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-string-time-zone-annotation.js38
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-string-unknown-annotation.js32
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-string-with-utc-designator.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-wrong-type.js43
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-zoneddatetime-convert.js22
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-zoneddatetime-slots.js40
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js23
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/basic.js21
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/branding.js27
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/browser.js0
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/builtin.js36
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/calendar-datefromfields-called-with-options-undefined.js18
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/calendar-fields-iterable.js37
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/calendar-temporal-object.js31
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/date-time.js23
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/date.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/infinity-throws-rangeerror.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/length.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/month-day-throw-type-error.js23
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/name.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/not-a-constructor.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/prop-desc.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/shell.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/string.js22
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/throw-range-error-ToTemporalDate.js22
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/year-month.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/year-zero.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-builtin-calendar-no-array-iteration.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-calendar-datefromfields-called-with-null-prototype-fields.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-constructor-in-calendar-fields.js17
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-duplicate-calendar-fields.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-leap-second.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-number.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-propertybag-calendar-case-insensitive.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-propertybag-calendar-leap-second.js23
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-propertybag-calendar-number.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-propertybag-calendar-string.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-propertybag-calendar-wrong-type.js46
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-propertybag-calendar-year-zero.js27
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-proto-in-calendar-fields.js17
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-string-calendar-annotation.js33
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-string-critical-unknown-annotation.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-string-date-with-utc-offset.js48
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-string-invalid.js64
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-string-multiple-calendar.js32
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-string-multiple-time-zone.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-string-time-separators.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-string-time-zone-annotation.js38
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-string-unknown-annotation.js32
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-string-with-utc-designator.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-wrong-type.js43
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-zoneddatetime-convert.js22
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-zoneddatetime-slots.js40
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js23
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/basic.js21
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/branding.js27
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/browser.js0
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/builtin.js36
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/calendar-datefromfields-called-with-options-undefined.js18
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/calendar-fields-iterable.js37
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/calendar-temporal-object.js31
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/date-time.js23
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/date.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/infinity-throws-rangeerror.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/length.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/month-day.js23
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/name.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/not-a-constructor.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/prop-desc.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/shell.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/string.js25
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/throw-range-error-ToTemporalDate.js22
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/year-month.js23
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/year-zero.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/basic.js51
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/branding.js27
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/browser.js0
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/builtin.js36
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/fields-missing-properties.js31
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/fields-not-object.js17
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/infinity-throws-rangeerror.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/length.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/missing-properties.js39
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/monthcode-invalid.js34
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/name.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/not-a-constructor.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/one-of-era-erayear-undefined.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/options-object.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/options-wrong-type.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/order-of-operations.js49
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/overflow-constrain.js68
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/overflow-invalid-string.js30
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/overflow-reject.js65
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/overflow-undefined.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/overflow-wrong-type.js27
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/prop-desc.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/shell.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-builtin-calendar-no-array-iteration.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-calendar-datefromfields-called-with-null-prototype-fields.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-constructor-in-calendar-fields.js17
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-duplicate-calendar-fields.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-leap-second.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-number.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-propertybag-calendar-case-insensitive.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-propertybag-calendar-leap-second.js23
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-propertybag-calendar-number.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-propertybag-calendar-string.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-propertybag-calendar-wrong-type.js46
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-propertybag-calendar-year-zero.js27
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-proto-in-calendar-fields.js17
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string-calendar-annotation.js33
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string-critical-unknown-annotation.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string-date-with-utc-offset.js48
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string-invalid.js64
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string-multiple-calendar.js32
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string-multiple-time-zone.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string-time-separators.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string-time-zone-annotation.js38
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string-unknown-annotation.js32
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string-with-utc-designator.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string.js21
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-wrong-type.js43
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-zoneddatetime-convert.js22
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-zoneddatetime-slots.js40
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js23
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/basic.js20
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/branding.js27
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/browser.js0
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/builtin.js36
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/calendar-datefromfields-called-with-options-undefined.js18
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/calendar-fields-iterable.js35
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/calendar-temporal-object.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/infinity-throws-rangeerror.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/length.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/name.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/not-a-constructor.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/prop-desc.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/shell.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/year-zero.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/prop-desc.js21
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/shell.js0
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toJSON/branding.js25
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toJSON/browser.js0
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toJSON/builtin.js36
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toJSON/length.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toJSON/name.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toJSON/not-a-constructor.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toJSON/prop-desc.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toJSON/returns-identifier-slot.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toJSON/shell.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toString/branding.js25
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toString/browser.js0
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toString/builtin.js36
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toString/length.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toString/name.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toString/not-a-constructor.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toString/prop-desc.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toString/shell.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toStringTag/browser.js0
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toStringTag/prop-desc.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toStringTag/shell.js0
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-builtin-calendar-no-array-iteration.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-calendar-datefromfields-called-with-null-prototype-fields.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-constructor-in-calendar-fields.js17
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-duplicate-calendar-fields.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-leap-second.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-number.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-plaindate.js79
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-plaindatetime.js79
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-propertybag-calendar-case-insensitive.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-propertybag-calendar-leap-second.js23
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-propertybag-calendar-number.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-propertybag-calendar-string.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-propertybag-calendar-wrong-type.js46
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-propertybag-calendar-year-zero.js27
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-proto-in-calendar-fields.js17
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string-calendar-annotation.js33
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string-critical-unknown-annotation.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string-date-with-utc-offset.js48
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string-invalid.js64
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string-multiple-calendar.js32
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string-multiple-time-zone.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string-time-separators.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string-time-zone-annotation.js38
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string-unknown-annotation.js32
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string-with-utc-designator.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string.js42
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-wrong-type.js43
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-zoneddatetime-convert.js22
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-zoneddatetime-slots.js40
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js23
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/basic.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/branding.js27
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/browser.js0
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/builtin.js36
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/calendar-datefromfields-called-with-options-undefined.js18
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/calendar-fields-iterable.js35
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/calendar-temporal-object.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/cross-year.js15
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/infinity-throws-rangeerror.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/length.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/name.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/not-a-constructor.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/prop-desc.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/shell.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/year-zero.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-builtin-calendar-no-array-iteration.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-calendar-datefromfields-called-with-null-prototype-fields.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-constructor-in-calendar-fields.js17
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-duplicate-calendar-fields.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-leap-second.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-number.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-propertybag-calendar-case-insensitive.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-propertybag-calendar-leap-second.js23
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-propertybag-calendar-number.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-propertybag-calendar-string.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-propertybag-calendar-wrong-type.js46
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-propertybag-calendar-year-zero.js27
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-proto-in-calendar-fields.js17
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-string-calendar-annotation.js33
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-string-critical-unknown-annotation.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-string-date-with-utc-offset.js48
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-string-invalid.js64
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-string-multiple-calendar.js32
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-string-multiple-time-zone.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-string-time-separators.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-string-time-zone-annotation.js38
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-string-unknown-annotation.js32
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-string-with-utc-designator.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-wrong-type.js43
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-zoneddatetime-convert.js22
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-zoneddatetime-slots.js40
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js23
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/basic.js20
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/branding.js27
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/browser.js0
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/builtin.js36
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/calendar-datefromfields-called-with-options-undefined.js18
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/calendar-fields-iterable.js37
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/calendar-temporal-object.js31
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/date-time.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/date.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/infinity-throws-rangeerror.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/length.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/name.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/not-a-constructor.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/prop-desc.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/shell.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/string.js23
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/throw-range-error-ToTemporalDate.js22
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/year-month.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/year-zero.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/basic.js43
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/branding.js27
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/browser.js0
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/builtin.js36
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/fields-missing-properties.js25
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/fields-not-object.js17
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/infinity-throws-rangeerror.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/length.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/missing-properties.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/monthcode-invalid.js34
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/name.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/not-a-constructor.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/one-of-era-erayear-undefined.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/options-not-object.js20
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/options-object.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/options-wrong-type.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/order-of-operations.js45
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/overflow-constrain.js94
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/overflow-invalid-string.js30
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/overflow-reject.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/overflow-undefined.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/overflow-wrong-type.js27
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/prop-desc.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/reference-day.js41
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/shell.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-builtin-calendar-no-array-iteration.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-calendar-datefromfields-called-with-null-prototype-fields.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-constructor-in-calendar-fields.js17
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-duplicate-calendar-fields.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-leap-second.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-number.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-propertybag-calendar-case-insensitive.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-propertybag-calendar-leap-second.js23
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-propertybag-calendar-number.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-propertybag-calendar-string.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-propertybag-calendar-wrong-type.js46
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-propertybag-calendar-year-zero.js27
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-proto-in-calendar-fields.js17
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-calendar-annotation.js33
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-critical-unknown-annotation.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-date-with-utc-offset.js48
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-invalid.js64
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-multiple-calendar.js32
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-multiple-time-zone.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-time-separators.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-time-zone-annotation.js38
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-unknown-annotation.js32
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-with-utc-designator.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string.js39
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-wrong-type.js43
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-convert.js22
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-slots.js40
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js23
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/basic.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/branding.js27
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/browser.js0
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/builtin.js36
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/calendar-datefromfields-called-with-options-undefined.js18
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/calendar-fields-iterable.js35
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/calendar-temporal-object.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/cross-year.js15
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/infinity-throws-rangeerror.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/length.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/name.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/not-a-constructor.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/prop-desc.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/shell.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/year-zero.js26
877 files changed, 25858 insertions, 0 deletions
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/browser.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/browser.js
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/constructor.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/constructor.js
new file mode 100644
index 0000000000..9b0bc3dc60
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/constructor.js
@@ -0,0 +1,20 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.constructor
+description: Test for Temporal.Calendar.prototype.constructor.
+info: The initial value of Temporal.Calendar.prototype.constructor is %Temporal.Calendar%.
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+verifyProperty(Temporal.Calendar.prototype, "constructor", {
+ value: Temporal.Calendar,
+ writable: true,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/add-days.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/add-days.js
new file mode 100644
index 0000000000..edf4f9b2f4
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/add-days.js
@@ -0,0 +1,39 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: Temporal.Calendar.prototype.dateAdd add duration with days and calculate correctly..
+info: |
+ 8. Let result be ? AddISODate(date.[[ISOYear]], date.[[ISOMonth]], date.[[ISODay]], duration.[[Years]], duration.[[Months]], duration.[[Weeks]], duration.[[Days]], overflow).
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+let p10d = new Temporal.Duration(0,0,0,10);
+
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2021-07-16", p10d), 2021, 7, "M07", 26,
+ "add 10 days and result into the same month");
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2021-07-26", p10d), 2021, 8, "M08", 5,
+ "add 10 days and result into next month");
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2021-12-26", p10d), 2022, 1, "M01", 5,
+ "add 10 days and result into next year");
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2020-02-26", p10d), 2020, 3, "M03", 7,
+ "add 10 days from a leap year in Feb and result into March");
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2021-02-26", p10d), 2021, 3, "M03", 8,
+ "add 10 days from a non leap year in Feb and result into March");
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2020-02-19", p10d), 2020, 2, "M02", 29,
+ "add 10 days from a leap year in Feb 19 and result into Feb 29");
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2021-02-19", p10d), 2021, 3, "M03", 1,
+ "add 10 days from a non leap year in Feb 19 and result into March 1");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/add-months-weeks.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/add-months-weeks.js
new file mode 100644
index 0000000000..7f3ac6e052
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/add-months-weeks.js
@@ -0,0 +1,39 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: Temporal.Calendar.prototype.dateAdd add duration with months and weeks and calculate correctly.
+info: |
+ 8. Let result be ? AddISODate(date.[[ISOYear]], date.[[ISOMonth]], date.[[ISODay]], duration.[[Years]], duration.[[Months]], duration.[[Weeks]], duration.[[Days]], overflow).
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+let p2m3w = new Temporal.Duration(0,2,3);
+
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2020-02-29", p2m3w), 2020, 5, "M05", 20,
+ "add two months 3 weeks from Feb 29 of a leap year");
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2020-02-28", p2m3w), 2020, 5, "M05", 19,
+ "add two months 3 weeks from Feb 28 of a leap year");
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2021-02-28", p2m3w), 2021, 5, "M05", 19,
+ "add two months 3 weeks from Feb 28 of a non leap year");
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2020-12-28", p2m3w), 2021, 3, "M03", 21,
+ "add two months 3 weeks from end of year to non leap year");
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2019-12-28", p2m3w), 2020, 3, "M03", 20,
+ "add two months 3 weeks from end of year to leap year");
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2019-10-28", p2m3w), 2020, 1, "M01", 18,
+ "add two months 3 weeks and cause roll into a new year");
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2019-10-31", p2m3w), 2020, 1, "M01", 21,
+ "add two months 3 weeks and cause roll into a new year");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/add-months.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/add-months.js
new file mode 100644
index 0000000000..592b16f2fe
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/add-months.js
@@ -0,0 +1,36 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: Temporal.Calendar.prototype.dateAdd add duration with months and calculate correctly
+info: |
+ 8. Let result be ? AddISODate(date.[[ISOYear]], date.[[ISOMonth]], date.[[ISODay]], duration.[[Years]], duration.[[Months]], duration.[[Weeks]], duration.[[Days]], overflow).
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+let p5m = new Temporal.Duration(0, 5);
+
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2021-07-16", p5m), 2021, 12, "M12", 16,
+ "add five months and result in the same year");
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2021-08-16", p5m), 2022, 1, "M01", 16,
+ "add five months and result in the next year");
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2021-10-31", p5m), 2022, 3, "M03", 31,
+ "add five months and result in the next year in end of month");
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2019-10-01", p5m), 2020, 3, "M03", 1,
+ "add five months and result in the next year in end of month on leap year");
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2021-09-30", p5m), 2022, 2, "M02", 28,
+ "add five months and result in the nexdt year and constrain to Feb 28");
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2019-09-30", p5m), 2020, 2, "M02", 29,
+ "add five months and result in the nexdt year and constrain to Feb 29 on leap year");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/add-weeks-days.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/add-weeks-days.js
new file mode 100644
index 0000000000..9489dd63ea
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/add-weeks-days.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: Temporal.Calendar.prototype.dateAdd add duration with weeks and days and calculate correctly.
+info: |
+ 8. Let result be ? AddISODate(date.[[ISOYear]], date.[[ISOMonth]], date.[[ISODay]], duration.[[Years]], duration.[[Months]], duration.[[Weeks]], duration.[[Days]], overflow).
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+let p2w3d = new Temporal.Duration(0,0,2,3);
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2020-02-29", p2w3d), 2020, 3, "M03", 17,
+ "add 2 weeks and 3 days (17 days) from Feb 29 in a leap year and cause rolling into March");
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2021-02-28", p2w3d), 2021, 3, "M03", 17,
+ "add 2 weeks and 3 days (17 days) from Feb and cause rolling into March in a non leap year");
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2020-02-28", p2w3d), 2020, 3, "M03", 16,
+ "add 2 weeks and 3 days (17 days) from Feb and cause rolling into March in a leap year");
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2020-12-28", p2w3d), 2021, 1, "M01", 14,
+ "add 2 weeks and 3 days (17 days) and cause rolling into a new year");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/add-weeks.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/add-weeks.js
new file mode 100644
index 0000000000..671bd83bfe
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/add-weeks.js
@@ -0,0 +1,66 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: Temporal.Calendar.prototype.dateAdd add duration with weeks and calculate correctly.
+info: |
+ 8. Let result be ? AddISODate(date.[[ISOYear]], date.[[ISOMonth]], date.[[ISODay]], duration.[[Years]], duration.[[Months]], duration.[[Weeks]], duration.[[Days]], overflow).
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+let p1w = new Temporal.Duration(0,0,1);
+let p6w = new Temporal.Duration(0,0,6);
+
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2021-02-19", p1w), 2021, 2, "M02", 26,
+ "add one week in Feb");
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2021-02-27", p1w), 2021, 3, "M03", 6,
+ "add one week in Feb and result in March");
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2020-02-27", p1w), 2020, 3, "M03", 5,
+ "add one week in Feb and result in March in a leap year");
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2021-12-24", p1w), 2021, 12, "M12", 31,
+ "add one week and result in the last day of a year");
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2021-12-25", p1w), 2022, 1, "M01", 1,
+ "add one week and result in the first day of next year");
+
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2021-01-27", p1w), 2021, 2, "M02", 3,
+ "add one week and result in next month from a month with 31 days");
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2021-06-27", p1w), 2021, 7, "M07", 4,
+ "add one week and result in next month from a month with 30 days");
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2021-07-27", p1w), 2021, 8, "M08", 3,
+ "add one week and result in next month from a month with 31 days");
+
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2021-02-19", p6w), 2021, 4, "M04", 2,
+ "add six weeks and result in next month from Feb in a non leap year");
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2020-02-19", p6w), 2020, 4, "M04", 1,
+ "add six weeks and result in next month from Feb in a leap year");
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2021-12-24", p6w), 2022, 2, "M02", 4,
+ "add six weeks and result in the next year");
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2021-01-27", p6w), 2021, 3, "M03", 10,
+ "add six weeks and result in the same year");
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2020-01-27", p6w), 2020, 3, "M03", 9,
+ "add six weeks and result in the same year");
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2021-06-27", p6w), 2021, 8, "M08", 8,
+ "add six weeks and result in the same year crossing month of 30 and 31 days");
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2021-07-27", p6w), 2021, 9, "M09", 7,
+ "add six weeks and result in the same year crossing month of 31 and 31 days");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/add-years-months-days.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/add-years-months-days.js
new file mode 100644
index 0000000000..1a7c932a3d
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/add-years-months-days.js
@@ -0,0 +1,48 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: Temporal.Calendar.prototype.dateAdd add duration with years, months and days and calculate correctly.
+info: |
+ 8. Let result be ? AddISODate(date.[[ISOYear]], date.[[ISOMonth]], date.[[ISODay]], duration.[[Years]], duration.[[Months]], duration.[[Weeks]], duration.[[Days]], overflow).
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+let p1y2m4d = new Temporal.Duration(1,2,0,4);
+
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2021-07-16", p1y2m4d), 2022, 9, "M09", 20,
+ "add one year two months and 4 days");
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2021-02-27", p1y2m4d), 2022, 5, "M05", 1,
+ "add one year two months and 4 days and roll into new month from a month of 30 days");
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2021-01-28", p1y2m4d), 2022, 4, "M04", 1,
+ "add one year two months and 4 days and roll into new month from a month of 31 days");
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2021-02-26", p1y2m4d), 2022, 4, "M04", 30,
+ "add one year two months and 4 days which roll from March to April in a non leap year");
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2023-02-26", p1y2m4d), 2024, 4, "M04", 30,
+ "add one year two months and 4 days which roll from March to April in a leap year");
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2021-12-30", p1y2m4d), 2023, 3, "M03", 4,
+ "add one year two months and 4 days which roll month into new year and roll day into March in non leap year");
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2022-12-30", p1y2m4d), 2024, 3, "M03", 4,
+ "add one year two months and 4 days which roll month into new year and roll day into March in leap year");
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2022-12-29", p1y2m4d), 2024, 3, "M03", 4,
+ "add one year two months and 4 days which roll month into new year and roll day into March in leap year");
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2021-07-30", p1y2m4d), 2022, 10, "M10", 4,
+ "add one year two months and 4 days which roll into a new month from a month with 30 days");
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2021-06-30", p1y2m4d), 2022, 9, "M09", 3,
+ "add one year two months and 4 days which roll into a new month from a month with 31 days");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/add-years-months.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/add-years-months.js
new file mode 100644
index 0000000000..4a3d984335
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/add-years-months.js
@@ -0,0 +1,30 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: Temporal.Calendar.prototype.dateAdd add duration with years and months and calculate correctly.
+info: |
+ 8. Let result be ? AddISODate(date.[[ISOYear]], date.[[ISOMonth]], date.[[ISODay]], duration.[[Years]], duration.[[Months]], duration.[[Weeks]], duration.[[Days]], overflow).
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+let p1y2m = new Temporal.Duration(1,2);
+
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2021-07-16", p1y2m), 2022, 9, "M09", 16,
+ "add one year and 2 months");
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2021-11-30", p1y2m), 2023, 1, "M01", 30,
+ "add one year and 2 months roll into a new year");
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2021-12-31", p1y2m), 2023, 2, "M02", 28,
+ "add one year and 2 months roll into a new year and constrain in Feb 28 of a non leap year");
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2022-12-31", p1y2m), 2024, 2, "M02", 29,
+ "add one year and 2 months roll into a new year and constrain in Feb 29 of a leap year");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/add-years-weeks.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/add-years-weeks.js
new file mode 100644
index 0000000000..06bae12e5a
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/add-years-weeks.js
@@ -0,0 +1,33 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: Temporal.Calendar.prototype.dateAdd add duration with years and weeks and calculate correctly.
+info: |
+ 8. Let result be ? AddISODate(date.[[ISOYear]], date.[[ISOMonth]], date.[[ISODay]], duration.[[Years]], duration.[[Months]], duration.[[Weeks]], duration.[[Days]], overflow).
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+let p1y2w = new Temporal.Duration(1,0,2);
+
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2020-02-28", p1y2w), 2021, 3, "M03", 14,
+ "add 1 year and 2 weeks to Feb 28 and cause roll into March in a non leap year");
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2020-02-29", p1y2w), 2021, 3, "M03", 14,
+ "add 1 year and 2 weeks to Feb 29 and cause roll into March in a non leap year");
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2019-02-28", p1y2w), 2020, 3, "M03", 13,
+ "add 1 year and 2 weeks to Feb 28 and cause roll into March in a leap year");
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2021-02-28", p1y2w), 2022, 3, "M03", 14,
+ "add 1 year and 2 weeks to Feb 28 and cause roll into March in a non leap year");
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2020-12-28", p1y2w), 2022, 1, "M01", 11,
+ "add 1 year and 2 weeks and cause roll into a new year");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/add-years.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/add-years.js
new file mode 100644
index 0000000000..c2e2eda6c5
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/add-years.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: Temporal.Calendar.prototype.dateAdd add duration with years only calculate correctly.
+info: |
+ 8. Let result be ? AddISODate(date.[[ISOYear]], date.[[ISOMonth]], date.[[ISODay]], duration.[[Years]], duration.[[Months]], duration.[[Weeks]], duration.[[Days]], overflow).
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+let p1y = new Temporal.Duration(1);
+let p4y = new Temporal.Duration(4);
+
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2020-02-29", p1y), 2021, 2, "M02", 28,
+ "add one year on Feb 29");
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2020-02-29", p4y), 2024, 2, "M02", 29,
+ "add four years on Feb 29");
+TemporalHelpers.assertPlainDate(
+ cal.dateAdd("2021-07-16", p1y), 2022, 7, "M07", 16,
+ "add one year on other date");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-builtin-calendar-no-array-iteration.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-builtin-calendar-no-array-iteration.js
new file mode 100644
index 0000000000..2d9cb13d16
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-builtin-calendar-no-array-iteration.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: >
+ Calling the method with a property bag argument with a builtin calendar causes
+ no observable array iteration when getting the calendar fields.
+features: [Temporal]
+---*/
+
+const arrayPrototypeSymbolIteratorOriginal = Array.prototype[Symbol.iterator];
+Array.prototype[Symbol.iterator] = function arrayIterator() {
+ throw new Test262Error("Array should not be iterated");
+}
+
+const instance = new Temporal.Calendar("iso8601");
+const arg = { year: 2000, month: 5, day: 2, calendar: "iso8601" };
+instance.dateAdd(arg, new Temporal.Duration());
+
+Array.prototype[Symbol.iterator] = arrayPrototypeSymbolIteratorOriginal;
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-calendar-datefromfields-called-with-null-prototype-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-calendar-datefromfields-called-with-null-prototype-fields.js
new file mode 100644
index 0000000000..6a0f1f43b0
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-calendar-datefromfields-called-with-null-prototype-fields.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: >
+ Calendar.dateFromFields method is called with a null-prototype fields object
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarCheckFieldsPrototypePollution();
+const instance = new Temporal.Calendar("iso8601");
+const arg = { year: 2000, month: 5, day: 2, calendar };
+instance.dateAdd(arg, new Temporal.Duration());
+assert.sameValue(calendar.dateFromFieldsCallCount, 1, "dateFromFields should be called on the property bag's calendar");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-constructor-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-constructor-in-calendar-fields.js
new file mode 100644
index 0000000000..897312501c
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-constructor-in-calendar-fields.js
@@ -0,0 +1,17 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: If a calendar's fields() method returns a field named 'constructor', PrepareTemporalFields should throw a RangeError.
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarWithExtraFields(['constructor']);
+const arg = {year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar};
+const instance = new Temporal.Calendar("iso8601");
+
+assert.throws(RangeError, () => instance.dateAdd(arg, new Temporal.Duration()));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-duplicate-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-duplicate-calendar-fields.js
new file mode 100644
index 0000000000..1ad3bc8141
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-duplicate-calendar-fields.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: If a calendar's fields() method returns duplicate field names, PrepareTemporalFields should throw a RangeError.
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+for (const extra_fields of [['foo', 'foo'], ['day'], ['month'], ['monthCode'], ['year']]) {
+ const calendar = TemporalHelpers.calendarWithExtraFields(extra_fields);
+ const arg = { year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar };
+ const instance = new Temporal.Calendar("iso8601");
+
+ assert.throws(RangeError, () => instance.dateAdd(arg, new Temporal.Duration()));
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-duration-max.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-duration-max.js
new file mode 100644
index 0000000000..b6cc1edb0c
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-duration-max.js
@@ -0,0 +1,58 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: Maximum allowed duration
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const maxCases = [
+ ["P273790Y8M12DT23H59M59.999999999S", "string with max years"],
+ [{ years: 273790, months: 8, days: 12, nanoseconds: 86399999999999 }, "property bag with max years"],
+ ["P3285488M12DT23H59M59.999999999S", "string with max months"],
+ [{ months: 3285488, days: 12, nanoseconds: 86399999999999 }, "property bag with max months"],
+ ["P14285714W2DT23H59M59.999999999S", "string with max weeks"],
+ [{ weeks: 14285714, days: 2, nanoseconds: 86399999999999 }, "property bag with max weeks"],
+ ["P100000000DT23H59M59.999999999S", "string with max days"],
+ [{ days: 100000000, nanoseconds: 86399999999999 }, "property bag with max days"],
+ ["PT2400000023H59M59.999999999S", "string with max hours"],
+ [{ hours: 2400000023, nanoseconds: 3599999999999 }, "property bag with max hours"],
+ ["PT144000001439M59.999999999S", "string with max minutes"],
+ [{ minutes: 144000001439, nanoseconds: 59999999999 }, "property bag with max minutes"],
+ ["PT8640000086399.999999999S", "string with max seconds"],
+ [{ seconds: 8640000086399, nanoseconds: 999999999 }, "property bag with max seconds"],
+];
+
+for (const [arg, descr] of maxCases) {
+ const result = instance.dateAdd(new Temporal.PlainDate(1970, 1, 1), arg);
+ TemporalHelpers.assertPlainDate(result, 275760, 9, "M09", 13, `operation succeeds with ${descr}`);
+}
+
+const minCases = [
+ ["-P273790Y8M12DT23H59M59.999999999S", "string with min years"],
+ [{ years: -273790, months: -8, days: -12, nanoseconds: -86399999999999 }, "property bag with min years"],
+ ["-P3285488M12DT23H59M59.999999999S", "string with min months"],
+ [{ months: -3285488, days: -12, nanoseconds: -86399999999999 }, "property bag with min months"],
+ ["-P14285714W3DT23H59M59.999999999S", "string with min weeks"],
+ [{ weeks: -14285714, days: -3, nanoseconds: -86399999999999 }, "property bag with min weeks"],
+ ["-P100000001DT23H59M59.999999999S", "string with min days"],
+ [{ days: -100000001, nanoseconds: -86399999999999 }, "property bag with min days"],
+ ["-PT2400000047H59M59.999999999S", "string with min hours"],
+ [{ hours: -2400000047, nanoseconds: -3599999999999 }, "property bag with min hours"],
+ ["-PT144000002879M59.999999999S", "string with min minutes"],
+ [{ minutes: -144000002879, nanoseconds: -59999999999 }, "property bag with min minutes"],
+ ["-PT8640000172799.999999999S", "string with min seconds"],
+ [{ seconds: -8640000172799, nanoseconds: -999999999 }, "property bag with min seconds"],
+];
+
+for (const [arg, descr] of minCases) {
+ const result = instance.dateAdd(new Temporal.PlainDate(1970, 1, 1), arg);
+ TemporalHelpers.assertPlainDate(result, -271821, 4, "M04", 19, `operation succeeds with ${descr}`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-duration-out-of-range.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-duration-out-of-range.js
new file mode 100644
index 0000000000..4368522992
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-duration-out-of-range.js
@@ -0,0 +1,75 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: Duration-like argument that is out of range
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const cases = [
+ // 2^32 = 4294967296
+ ["P4294967296Y", "string with years > max"],
+ [{ years: 4294967296 }, "property bag with years > max"],
+ ["-P4294967296Y", "string with years < min"],
+ [{ years: -4294967296 }, "property bag with years < min"],
+ ["P4294967296M", "string with months > max"],
+ [{ months: 4294967296 }, "property bag with months > max"],
+ ["-P4294967296M", "string with months < min"],
+ [{ months: -4294967296 }, "property bag with months < min"],
+ ["P4294967296W", "string with weeks > max"],
+ [{ weeks: 4294967296 }, "property bag with weeks > max"],
+ ["-P4294967296W", "string with weeks < min"],
+ [{ weeks: -4294967296 }, "property bag with weeks < min"],
+
+ // ceil(max safe integer / 86400) = 104249991375
+ ["P104249991375D", "string with days > max"],
+ [{ days: 104249991375 }, "property bag with days > max"],
+ ["P104249991374DT24H", "string where hours balance into days > max"],
+ [{ days: 104249991374, hours: 24 }, "property bag where hours balance into days > max"],
+ ["-P104249991375D", "string with days < min"],
+ [{ days: -104249991375 }, "property bag with days < min"],
+ ["-P104249991374DT24H", "string where hours balance into days < min"],
+ [{ days: -104249991374, hours: -24 }, "property bag where hours balance into days < min"],
+
+ // ceil(max safe integer / 3600) = 2501999792984
+ ["PT2501999792984H", "string with hours > max"],
+ [{ hours: 2501999792984 }, "property bag with hours > max"],
+ ["PT2501999792983H60M", "string where minutes balance into hours > max"],
+ [{ hours: 2501999792983, minutes: 60 }, "property bag where minutes balance into hours > max"],
+ ["-PT2501999792984H", "string with hours < min"],
+ [{ hours: -2501999792984 }, "property bag with hours < min"],
+ ["-PT2501999792983H60M", "string where minutes balance into hours < min"],
+ [{ hours: -2501999792983, minutes: -60 }, "property bag where minutes balance into hours < min"],
+
+ // ceil(max safe integer / 60) = 150119987579017
+ ["PT150119987579017M", "string with minutes > max"],
+ [{ minutes: 150119987579017 }, "property bag with minutes > max"],
+ ["PT150119987579016M60S", "string where seconds balance into minutes > max"],
+ [{ minutes: 150119987579016, seconds: 60 }, "property bag where seconds balance into minutes > max"],
+ ["-PT150119987579017M", "string with minutes < min"],
+ [{ minutes: -150119987579017 }, "property bag with minutes < min"],
+ ["-PT150119987579016M60S", "string where seconds balance into minutes < min"],
+ [{ minutes: -150119987579016, seconds: -60 }, "property bag where seconds balance into minutes < min"],
+
+ // 2^53 = 9007199254740992
+ ["PT9007199254740992S", "string with seconds > max"],
+ [{ seconds: 9007199254740992 }, "property bag with seconds > max"],
+ [{ seconds: 9007199254740991, milliseconds: 1000 }, "property bag where milliseconds balance into seconds > max"],
+ [{ seconds: 9007199254740991, microseconds: 1000000 }, "property bag where microseconds balance into seconds > max"],
+ [{ seconds: 9007199254740991, nanoseconds: 1000000000 }, "property bag where nanoseconds balance into seconds > max"],
+ ["-PT9007199254740992S", "string with seconds < min"],
+ [{ seconds: -9007199254740992 }, "property bag with seconds < min"],
+ [{ seconds: -9007199254740991, milliseconds: -1000 }, "property bag where milliseconds balance into seconds < min"],
+ [{ seconds: -9007199254740991, microseconds: -1000000 }, "property bag where microseconds balance into seconds < min"],
+ [{ seconds: -9007199254740991, nanoseconds: -1000000000 }, "property bag where nanoseconds balance into seconds < min"],
+];
+
+for (const [arg, descr] of cases) {
+ assert.throws(RangeError, () => instance.dateAdd(new Temporal.PlainDate(1970, 1, 1), arg), `${descr} is out of range`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-duration-years-and-months-number-max-value.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-duration-years-and-months-number-max-value.js
new file mode 100644
index 0000000000..dcbfed8b43
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-duration-years-and-months-number-max-value.js
@@ -0,0 +1,38 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: >
+ Call BalanceISOYearMonth with 2³² - 1 and -(2³² - 1) for years/months.
+info: |
+ Temporal.Calendar.prototype.dateAdd ( date, duration [ , options ] )
+
+ ...
+ 9. Let result be ? AddISODate(date.[[ISOYear]], date.[[ISOMonth]], date.[[ISODay]],
+ duration.[[Years]], duration.[[Months]], duration.[[Weeks]], balanceResult.[[Days]],
+ overflow).
+ 10. Return ? CreateTemporalDate(result.[[Year]], result.[[Month]], result.[[Day]], calendar).
+
+ AddISODate ( year, month, day, years, months, weeks, days, overflow )
+
+ ...
+ 3. Let intermediate be ! BalanceISOYearMonth(year + years, month + months).
+ ...
+
+features: [Temporal]
+---*/
+
+var cal = new Temporal.Calendar("iso8601");
+var date = new Temporal.PlainDate(1970, 1, 1);
+
+const max = 4294967295; // 2³² - 1
+
+var maxValue = new Temporal.Duration(max, max);
+var minValue = new Temporal.Duration(-max, -max);
+
+assert.throws(RangeError, () => cal.dateAdd(date, maxValue), "years/months is +Number.MAX_VALUE");
+assert.throws(RangeError, () => cal.dateAdd(date, minValue), "years/months is -Number.MAX_VALUE");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-leap-second.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-leap-second.js
new file mode 100644
index 0000000000..edca559552
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-leap-second.js
@@ -0,0 +1,30 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: Leap second is a valid ISO string for PlainDate
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+let arg = "2016-12-31T23:59:60";
+const result1 = instance.dateAdd(arg, new Temporal.Duration());
+TemporalHelpers.assertPlainDate(
+ result1,
+ 2016, 12, "M12", 31,
+ "leap second is a valid ISO string for PlainDate"
+);
+
+arg = { year: 2016, month: 12, day: 31, hour: 23, minute: 59, second: 60 };
+const result2 = instance.dateAdd(arg, new Temporal.Duration());
+TemporalHelpers.assertPlainDate(
+ result2,
+ 2016, 12, "M12", 31,
+ "second: 60 is ignored in property bag for PlainDate"
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-number.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-number.js
new file mode 100644
index 0000000000..940952dd15
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-number.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: A number cannot be used in place of a Temporal.PlainDate
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const numbers = [
+ 1,
+ 19761118,
+ -19761118,
+ 1234567890,
+];
+
+for (const arg of numbers) {
+ assert.throws(
+ TypeError,
+ () => instance.dateAdd(arg, new Temporal.Duration()),
+ 'Numbers cannot be used in place of an ISO string for PlainDate'
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-plaindatetime.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-plaindatetime.js
new file mode 100644
index 0000000000..a613cfe71e
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-plaindatetime.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: Fast path for converting Temporal.PlainDateTime to Temporal.PlainDate by reading internal slots
+info: |
+ sec-temporal.calendar.prototype.dateadd step 4:
+ 4. Set _date_ to ? ToTemporalDate(_date_).
+ sec-temporal-totemporaldate step 2.b:
+ b. If _item_ has an [[InitializedTemporalDateTime]] internal slot, then
+ i. Return ! CreateTemporalDate(_item_.[[ISOYear]], _item_.[[ISOMonth]], _item_.[[ISODay]], _item_.[[Calendar]]).
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+TemporalHelpers.checkPlainDateTimeConversionFastPath((datetime) => {
+ const calendar = new Temporal.Calendar("iso8601");
+ const duration = new Temporal.Duration(0, 1);
+ const result = calendar.dateAdd(datetime, duration);
+ TemporalHelpers.assertPlainDate(result, 2000, 6, "M06", 2);
+ assert.sameValue(result.hour, undefined, "instance of PlainDate returned, not PlainDateTime");
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-propertybag-calendar-case-insensitive.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-propertybag-calendar-case-insensitive.js
new file mode 100644
index 0000000000..b09b2939c2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-propertybag-calendar-case-insensitive.js
@@ -0,0 +1,20 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: The calendar name is case-insensitive
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const calendar = "IsO8601";
+
+const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+const result = instance.dateAdd(arg, new Temporal.Duration());
+TemporalHelpers.assertPlainDate(result, 1976, 11, "M11", 18, "Calendar is case-insensitive");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-propertybag-calendar-leap-second.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-propertybag-calendar-leap-second.js
new file mode 100644
index 0000000000..7517d61c18
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-propertybag-calendar-leap-second.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: Leap second is a valid ISO string for a calendar in a property bag
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const calendar = "2016-12-31T23:59:60";
+
+const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+const result = instance.dateAdd(arg, new Temporal.Duration());
+TemporalHelpers.assertPlainDate(
+ result,
+ 1976, 11, "M11", 18,
+ "leap second is a valid ISO string for calendar"
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-propertybag-calendar-number.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-propertybag-calendar-number.js
new file mode 100644
index 0000000000..80b3fcd76f
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-propertybag-calendar-number.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: A number as calendar in a property bag is not accepted
+features: [Temporal]
+---*/
+
+const instance = new Temporal.PlainDate(1976, 11, 18);
+
+const numbers = [
+ 1,
+ 19970327,
+ -19970327,
+ 1234567890,
+];
+for (const calendar of numbers) {
+ const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+ assert.throws(
+ TypeError,
+ () => instance.dateAdd(arg, new Temporal.Duration()),
+ "Numbers cannot be used as a calendar"
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-propertybag-calendar-string.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-propertybag-calendar-string.js
new file mode 100644
index 0000000000..cb12bd134f
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-propertybag-calendar-string.js
@@ -0,0 +1,20 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: A calendar ID is valid input for Calendar
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const calendar = "iso8601";
+
+const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+const result = instance.dateAdd(arg, new Temporal.Duration());
+TemporalHelpers.assertPlainDate(result, 1976, 11, "M11", 18, `Calendar created from string "${calendar}"`);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-propertybag-calendar-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-propertybag-calendar-wrong-type.js
new file mode 100644
index 0000000000..72fbbce9da
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-propertybag-calendar-wrong-type.js
@@ -0,0 +1,46 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: >
+ Appropriate error thrown when a calendar property from a property bag cannot
+ be converted to a calendar object or string
+features: [BigInt, Symbol, Temporal]
+---*/
+
+const timeZone = new Temporal.TimeZone("UTC");
+const instance = new Temporal.Calendar("iso8601");
+
+const primitiveTests = [
+ [null, "null"],
+ [true, "boolean"],
+ ["", "empty string"],
+ [1, "number that doesn't convert to a valid ISO string"],
+ [1n, "bigint"],
+];
+
+for (const [calendar, description] of primitiveTests) {
+ const arg = { year: 2019, monthCode: "M11", day: 1, calendar };
+ assert.throws(
+ typeof calendar === 'string' ? RangeError : TypeError,
+ () => instance.dateAdd(arg, new Temporal.Duration()),
+ `${description} does not convert to a valid ISO string`
+ );
+}
+
+const typeErrorTests = [
+ [Symbol(), "symbol"],
+ [{}, "plain object that doesn't implement the protocol"],
+ [new Temporal.TimeZone("UTC"), "time zone instance"],
+ [Temporal.Calendar, "Temporal.Calendar, object"],
+ [Temporal.Calendar.prototype, "Temporal.Calendar.prototype, object"], // fails brand check in dateFromFields()
+];
+
+for (const [calendar, description] of typeErrorTests) {
+ const arg = { year: 2019, monthCode: "M11", day: 1, calendar };
+ assert.throws(TypeError, () => instance.dateAdd(arg, new Temporal.Duration()), `${description} is not a valid property bag and does not convert to a string`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-propertybag-calendar-year-zero.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-propertybag-calendar-year-zero.js
new file mode 100644
index 0000000000..2a93ec4ea9
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-propertybag-calendar-year-zero.js
@@ -0,0 +1,27 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: Negative zero, as an extended year, is rejected
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ "-000000-10-31",
+ "-000000-10-31T17:45",
+ "-000000-10-31T17:45Z",
+ "-000000-10-31T17:45+01:00",
+ "-000000-10-31T17:45+00:00[UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.dateAdd(arg, new Temporal.Duration()),
+ "reject minus zero as extended year"
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-proto-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-proto-in-calendar-fields.js
new file mode 100644
index 0000000000..4e49748823
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-proto-in-calendar-fields.js
@@ -0,0 +1,17 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: If a calendar's fields() method returns a field named '__proto__', PrepareTemporalFields should throw a RangeError.
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarWithExtraFields(['__proto__']);
+const arg = {year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar};
+const instance = new Temporal.Calendar("iso8601");
+
+assert.throws(RangeError, () => instance.dateAdd(arg, new Temporal.Duration()));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-calendar-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-calendar-annotation.js
new file mode 100644
index 0000000000..c14ecfd721
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-calendar-annotation.js
@@ -0,0 +1,34 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: Various forms of calendar annotation; critical flag has no effect
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+const tests = [
+ ["2000-05-02[u-ca=iso8601]", "without time or time zone"],
+ ["2000-05-02[UTC][u-ca=iso8601]", "with time zone and no time"],
+ ["2000-05-02T15:23[u-ca=iso8601]", "without time zone"],
+ ["2000-05-02T15:23[UTC][u-ca=iso8601]", "with time zone"],
+ ["2000-05-02T15:23[!u-ca=iso8601]", "with ! and no time zone"],
+ ["2000-05-02T15:23[UTC][!u-ca=iso8601]", "with ! and time zone"],
+ ["2000-05-02T15:23[u-ca=iso8601][u-ca=discord]", "second annotation ignored"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.dateAdd(arg, new Temporal.Duration());
+
+ TemporalHelpers.assertPlainDate(
+ result,
+ 2000, 5, "M05", 2,
+ `calendar annotation (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-critical-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-critical-unknown-annotation.js
new file mode 100644
index 0000000000..46728937ab
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-critical-unknown-annotation.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: Unknown annotations with critical flag are rejected
+features: [Temporal]
+---*/
+
+const invalidStrings = [
+ "1970-01-01[!foo=bar]",
+ "1970-01-01T00:00[!foo=bar]",
+ "1970-01-01T00:00[UTC][!foo=bar]",
+ "1970-01-01T00:00[u-ca=iso8601][!foo=bar]",
+ "1970-01-01T00:00[UTC][!foo=bar][u-ca=iso8601]",
+ "1970-01-01T00:00[foo=bar][!_foo-bar0=Dont-Ignore-This-99999999999]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.dateAdd(arg, new Temporal.Duration()),
+ `reject unknown annotation with critical flag: ${arg}`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-date-with-utc-offset.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-date-with-utc-offset.js
new file mode 100644
index 0000000000..3d3cde244a
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-date-with-utc-offset.js
@@ -0,0 +1,49 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: UTC offset not valid with format that does not include a time
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const validStrings = [
+ "2000-05-02T00+00:00",
+ "2000-05-02T00+00:00[UTC]",
+ "2000-05-02T00+00:00[!UTC]",
+ "2000-05-02T00-02:30[America/St_Johns]",
+];
+
+for (const arg of validStrings) {
+ const result = instance.dateAdd(arg, new Temporal.Duration());
+
+ TemporalHelpers.assertPlainDate(
+ result,
+ 2000, 5, "M05", 2,
+ `"${arg}" is a valid UTC offset with time for PlainDate`
+ );
+}
+
+const invalidStrings = [
+ "2022-09-15Z",
+ "2022-09-15Z[UTC]",
+ "2022-09-15Z[Europe/Vienna]",
+ "2022-09-15+00:00",
+ "2022-09-15+00:00[UTC]",
+ "2022-09-15-02:30",
+ "2022-09-15-02:30[America/St_Johns]",
+];
+
+for (const arg of invalidStrings) {
+ assert.throws(
+ RangeError,
+ () => instance.dateAdd(arg, new Temporal.Duration()),
+ `"${arg}" UTC offset without time is not valid for PlainDate`
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-invalid.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-invalid.js
new file mode 100644
index 0000000000..94cd428d07
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-invalid.js
@@ -0,0 +1,64 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: >
+ RangeError thrown if an invalid ISO string (or syntactically valid ISO string
+ that is not supported) is used as a PlainDate
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ // invalid ISO strings:
+ "",
+ "invalid iso8601",
+ "2020-01-00",
+ "2020-01-32",
+ "2020-02-30",
+ "2021-02-29",
+ "2020-00-01",
+ "2020-13-01",
+ "2020-01-01T",
+ "2020-01-01T25:00:00",
+ "2020-01-01T01:60:00",
+ "2020-01-01T01:60:61",
+ "2020-01-01junk",
+ "2020-01-01T00:00:00junk",
+ "2020-01-01T00:00:00+00:00junk",
+ "2020-01-01T00:00:00+00:00[UTC]junk",
+ "2020-01-01T00:00:00+00:00[UTC][u-ca=iso8601]junk",
+ "02020-01-01",
+ "2020-001-01",
+ "2020-01-001",
+ "2020-01-01T001",
+ "2020-01-01T01:001",
+ "2020-01-01T01:01:001",
+ // valid, but forms not supported in Temporal:
+ "2020-W01-1",
+ "2020-001",
+ "+0002020-01-01",
+ // valid, but this calendar must not exist:
+ "2020-01-01[u-ca=notexist]",
+ // may be valid in other contexts, but insufficient information for PlainDate:
+ "2020-01",
+ "+002020-01",
+ "01-01",
+ "2020-W01",
+ "P1Y",
+ "-P12Y",
+ // valid, but outside the supported range:
+ "-999999-01-01",
+ "+999999-01-01",
+];
+const instance = new Temporal.Calendar("iso8601");
+for (const arg of invalidStrings) {
+ assert.throws(
+ RangeError,
+ () => instance.dateAdd(arg, new Temporal.Duration()),
+ `"${arg}" should not be a valid ISO string for a PlainDate`
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-multiple-calendar.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-multiple-calendar.js
new file mode 100644
index 0000000000..edbc719aaf
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-multiple-calendar.js
@@ -0,0 +1,32 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: >
+ More than one calendar annotation is not syntactical if any have the criical
+ flag
+features: [Temporal]
+---*/
+
+const invalidStrings = [
+ "1970-01-01[u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01[!u-ca=iso8601][u-ca=iso8601]",
+ "1970-01-01[UTC][u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01[u-ca=iso8601][foo=bar][!u-ca=iso8601]",
+ "1970-01-01T00:00[u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01T00:00[!u-ca=iso8601][u-ca=iso8601]",
+ "1970-01-01T00:00[UTC][u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01T00:00[u-ca=iso8601][foo=bar][!u-ca=iso8601]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.dateAdd(arg, new Temporal.Duration()),
+ `reject more than one calendar annotation if any critical: ${arg}`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-multiple-time-zone.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-multiple-time-zone.js
new file mode 100644
index 0000000000..dfd6888026
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-multiple-time-zone.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: More than one time zone annotation is not syntactical
+features: [Temporal]
+---*/
+
+const invalidStrings = [
+ "1970-01-01[UTC][UTC]",
+ "1970-01-01T00:00[UTC][UTC]",
+ "1970-01-01T00:00[!UTC][UTC]",
+ "1970-01-01T00:00[UTC][!UTC]",
+ "1970-01-01T00:00[UTC][u-ca=iso8601][UTC]",
+ "1970-01-01T00:00[UTC][foo=bar][UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.dateAdd(arg, new Temporal.Duration()),
+ `reject more than one time zone annotation: ${arg}`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-time-separators.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-time-separators.js
new file mode 100644
index 0000000000..7480f0af4c
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-time-separators.js
@@ -0,0 +1,30 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: Time separator in string argument can vary
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+const tests = [
+ ["2000-05-02T15:23", "uppercase T"],
+ ["2000-05-02t15:23", "lowercase T"],
+ ["2000-05-02 15:23", "space between date and time"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.dateAdd(arg, new Temporal.Duration());
+
+ TemporalHelpers.assertPlainDate(
+ result,
+ 2000, 5, "M05", 2,
+ `variant time separators (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-time-zone-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-time-zone-annotation.js
new file mode 100644
index 0000000000..e436365b1c
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-time-zone-annotation.js
@@ -0,0 +1,39 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: Various forms of time zone annotation; critical flag has no effect
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+const tests = [
+ ["2000-05-02[Asia/Kolkata]", "named, with no time"],
+ ["2000-05-02[!Europe/Vienna]", "named, with ! and no time"],
+ ["2000-05-02[+00:00]", "numeric, with no time"],
+ ["2000-05-02[!-02:30]", "numeric, with ! and no time"],
+ ["2000-05-02T15:23[America/Sao_Paulo]", "named, with no offset"],
+ ["2000-05-02T15:23[!Asia/Tokyo]", "named, with ! and no offset"],
+ ["2000-05-02T15:23[-02:30]", "numeric, with no offset"],
+ ["2000-05-02T15:23[!+00:00]", "numeric, with ! and no offset"],
+ ["2000-05-02T15:23+00:00[America/New_York]", "named, with offset"],
+ ["2000-05-02T15:23+00:00[!UTC]", "named, with offset and !"],
+ ["2000-05-02T15:23+00:00[+01:00]", "numeric, with offset"],
+ ["2000-05-02T15:23+00:00[!-08:00]", "numeric, with offset and !"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.dateAdd(arg, new Temporal.Duration());
+
+ TemporalHelpers.assertPlainDate(
+ result,
+ 2000, 5, "M05", 2,
+ `time zone annotation (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-unknown-annotation.js
new file mode 100644
index 0000000000..f217d7e8b7
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-unknown-annotation.js
@@ -0,0 +1,33 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: Various forms of unknown annotation
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+const tests = [
+ ["2000-05-02[foo=bar]", "without time"],
+ ["2000-05-02T15:23[foo=bar]", "alone"],
+ ["2000-05-02T15:23[UTC][foo=bar]", "with time zone"],
+ ["2000-05-02T15:23[u-ca=iso8601][foo=bar]", "with calendar"],
+ ["2000-05-02T15:23[UTC][foo=bar][u-ca=iso8601]", "with time zone and calendar"],
+ ["2000-05-02T15:23[foo=bar][_foo-bar0=Ignore-This-999999999999]", "with another unknown annotation"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.dateAdd(arg, new Temporal.Duration());
+
+ TemporalHelpers.assertPlainDate(
+ result,
+ 2000, 5, "M05", 2,
+ `unknown annotation (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-with-utc-designator.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-with-utc-designator.js
new file mode 100644
index 0000000000..0bf4e2177a
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-with-utc-designator.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: RangeError thrown if a string with UTC designator is used as a PlainDate
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ "2019-10-01T09:00:00Z",
+ "2019-10-01T09:00:00Z[UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.dateAdd(arg, new Temporal.Duration()),
+ "String with UTC designator should not be valid as a PlainDate"
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-wrong-type.js
new file mode 100644
index 0000000000..0578415add
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-wrong-type.js
@@ -0,0 +1,43 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: >
+ Appropriate error thrown when argument cannot be converted to a valid string
+ or property bag for PlainDate
+features: [BigInt, Symbol, Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const primitiveTests = [
+ [undefined, "undefined"],
+ [null, "null"],
+ [true, "boolean"],
+ ["", "empty string"],
+ [1, "number that doesn't convert to a valid ISO string"],
+ [1n, "bigint"],
+];
+
+for (const [arg, description] of primitiveTests) {
+ assert.throws(
+ typeof arg === 'string' ? RangeError : TypeError,
+ () => instance.dateAdd(arg, new Temporal.Duration()),
+ `${description} does not convert to a valid ISO string`
+ );
+}
+
+const typeErrorTests = [
+ [Symbol(), "symbol"],
+ [{}, "plain object"],
+ [Temporal.PlainDate, "Temporal.PlainDate, object"],
+ [Temporal.PlainDate.prototype, "Temporal.PlainDate.prototype, object"],
+];
+
+for (const [arg, description] of typeErrorTests) {
+ assert.throws(TypeError, () => instance.dateAdd(arg, new Temporal.Duration()), `${description} is not a valid property bag and does not convert to a string`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-convert.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-convert.js
new file mode 100644
index 0000000000..3908fb2f29
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-convert.js
@@ -0,0 +1,22 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: An exception from TimeZone#getOffsetNanosecondsFor() is propagated.
+features: [Temporal]
+---*/
+
+class TZ extends Temporal.TimeZone {
+ constructor() { super("UTC") }
+ getOffsetNanosecondsFor() { throw new Test262Error() }
+}
+
+const tz = new TZ();
+const arg = new Temporal.ZonedDateTime(0n, tz);
+const instance = new Temporal.Calendar("iso8601");
+
+assert.throws(Test262Error, () => instance.dateAdd(arg, new Temporal.Duration()));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-slots.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-slots.js
new file mode 100644
index 0000000000..ef5dea755a
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-slots.js
@@ -0,0 +1,40 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: Getters are not called when converting a ZonedDateTime to a PlainDate.
+includes: [compareArray.js]
+features: [Temporal]
+---*/
+
+const actual = [];
+const prototypeDescrs = Object.getOwnPropertyDescriptors(Temporal.ZonedDateTime.prototype);
+const getters = ["year", "month", "monthCode", "day", "hour", "minute", "second", "millisecond", "microsecond", "nanosecond", "calendar"];
+
+for (const property of getters) {
+ Object.defineProperty(Temporal.ZonedDateTime.prototype, property, {
+ get() {
+ actual.push(`get ${property}`);
+ const value = prototypeDescrs[property].get.call(this);
+ return {
+ toString() {
+ actual.push(`toString ${property}`);
+ return value.toString();
+ },
+ valueOf() {
+ actual.push(`valueOf ${property}`);
+ return value;
+ },
+ };
+ },
+ });
+}
+
+const arg = new Temporal.ZonedDateTime(0n, "UTC");
+const instance = new Temporal.Calendar("iso8601");
+instance.dateAdd(arg, new Temporal.Duration());
+assert.compareArray(actual, []);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js
new file mode 100644
index 0000000000..9155340af0
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js
@@ -0,0 +1,20 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: RangeError thrown if time zone reports an offset that is not an integer number of nanoseconds
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+[3600_000_000_000.5, NaN, -Infinity, Infinity].forEach((wrongOffset) => {
+ const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset);
+ const calendar = new Temporal.Calendar("iso8601");
+ const duration = new Temporal.Duration(1);
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ assert.throws(RangeError, () => calendar.dateAdd(datetime, duration));
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js
new file mode 100644
index 0000000000..5356882df5
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: TypeError thrown if timeZone.getOffsetNanosecondsFor is not callable
+features: [BigInt, Symbol, Temporal, arrow-function]
+---*/
+
+[undefined, null, true, Math.PI, 'string', Symbol('sym'), 42n, {}].forEach((notCallable) => {
+ const timeZone = new Temporal.TimeZone("UTC");
+ const calendar = new Temporal.Calendar("iso8601");
+ const duration = new Temporal.Duration(1);
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ timeZone.getOffsetNanosecondsFor = notCallable;
+ assert.throws(
+ TypeError,
+ () => calendar.dateAdd(datetime, duration),
+ `Uncallable ${notCallable === null ? 'null' : typeof notCallable} getOffsetNanosecondsFor should throw TypeError`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js
new file mode 100644
index 0000000000..441f379188
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js
@@ -0,0 +1,20 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: RangeError thrown if time zone reports an offset that is out of range
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+[-86400_000_000_000, 86400_000_000_000].forEach((wrongOffset) => {
+ const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset);
+ const calendar = new Temporal.Calendar("iso8601");
+ const duration = new Temporal.Duration(1);
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ assert.throws(RangeError, () => calendar.dateAdd(datetime, duration));
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js
new file mode 100644
index 0000000000..4f7e73bdf3
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: TypeError thrown if time zone reports an offset that is not a Number
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+[
+ undefined,
+ null,
+ true,
+ "+01:00",
+ Symbol(),
+ 3600_000_000_000n,
+ {},
+ { valueOf() { return 3600_000_000_000; } },
+].forEach((wrongOffset) => {
+ const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset);
+ const calendar = new Temporal.Calendar("iso8601");
+ const duration = new Temporal.Duration(1);
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ assert.throws(TypeError, () => calendar.dateAdd(datetime, duration));
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/balance-smaller-units.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/balance-smaller-units.js
new file mode 100644
index 0000000000..398ca6999f
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/balance-smaller-units.js
@@ -0,0 +1,25 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: Durations with units smaller than days are balanced before adding
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = new Temporal.Calendar("iso8601");
+const date = new Temporal.PlainDate(2000, 5, 2, calendar);
+const duration = new Temporal.Duration(0, 0, 0, 1, 24, 1440, 86400, 86400_000, 86400_000_000, 86400_000_000_000);
+
+const result = calendar.dateAdd(date, duration);
+TemporalHelpers.assertPlainDate(result, 2000, 5, "M05", 9, "units smaller than days are balanced");
+
+const resultString = calendar.dateAdd(date, "P1DT24H1440M86400S");
+TemporalHelpers.assertPlainDate(resultString, 2000, 5, "M05", 6, "units smaller than days are balanced");
+
+const resultPropBag = calendar.dateAdd(date, { days: 1, hours: 24, minutes: 1440, seconds: 86400, milliseconds: 86400_000, microseconds: 86400_000_000, nanoseconds: 86400_000_000_000 });
+TemporalHelpers.assertPlainDate(resultPropBag, 2000, 5, "M05", 9, "units smaller than days are balanced");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/basic.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/basic.js
new file mode 100644
index 0000000000..2424570c74
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/basic.js
@@ -0,0 +1,53 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: Basic tests for dateAdd().
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const iso = Temporal.Calendar.from("iso8601");
+const date = Temporal.PlainDate.from("1994-11-06");
+const positiveDuration = Temporal.Duration.from({ months: 1, weeks: 1 });
+const negativeDuration = Temporal.Duration.from({ months: -1, weeks: -1 });
+
+TemporalHelpers.assertPlainDate(
+ iso.dateAdd(Temporal.PlainDateTime.from("1994-11-06T08:15:30"), positiveDuration, {}),
+ 1994, 12, "M12", 13, "date: PlainDateTime");
+
+TemporalHelpers.assertPlainDate(
+ iso.dateAdd({ year: 1994, month: 11, day: 6 }, positiveDuration, {}),
+ 1994, 12, "M12", 13, "date: property bag");
+
+TemporalHelpers.assertPlainDate(
+ iso.dateAdd("1994-11-06", positiveDuration, {}),
+ 1994, 12, "M12", 13, "date: string");
+
+assert.throws(TypeError, () => iso.dateAdd({ month: 11 }, positiveDuration, {}), "date: missing property");
+
+TemporalHelpers.assertPlainDate(
+ iso.dateAdd(date, { months: 1, weeks: 1 }, {}),
+ 1994, 12, "M12", 13, "duration: property bag");
+
+TemporalHelpers.assertPlainDate(
+ iso.dateAdd(date, "P1M1W", {}),
+ 1994, 12, "M12", 13, "duration: string");
+
+assert.throws(TypeError, () => iso.dateAdd(date, { month: 1 }, {}), "duration: missing property");
+
+TemporalHelpers.assertPlainDate(
+ iso.dateAdd(Temporal.PlainDateTime.from("1994-11-06T08:15:30"), negativeDuration, {}),
+ 1994, 9, "M09", 29, "date: PlainDateTime, negative duration");
+
+TemporalHelpers.assertPlainDate(
+ iso.dateAdd({ year: 1994, month: 11, day: 6 }, negativeDuration, {}),
+ 1994, 9, "M09", 29, "date: property bag, negative duration");
+
+TemporalHelpers.assertPlainDate(
+ iso.dateAdd("1994-11-06", negativeDuration, {}),
+ 1994, 9, "M09", 29, "date: string, negative duration");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/branding.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/branding.js
new file mode 100644
index 0000000000..c1db178920
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/branding.js
@@ -0,0 +1,27 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: Throw a TypeError if the receiver is invalid
+features: [Symbol, Temporal]
+---*/
+
+const dateAdd = Temporal.Calendar.prototype.dateAdd;
+
+assert.sameValue(typeof dateAdd, "function");
+
+const args = [new Temporal.PlainDate(2000, 1, 1), new Temporal.Duration(1)];
+
+assert.throws(TypeError, () => dateAdd.apply(undefined, args), "undefined");
+assert.throws(TypeError, () => dateAdd.apply(null, args), "null");
+assert.throws(TypeError, () => dateAdd.apply(true, args), "true");
+assert.throws(TypeError, () => dateAdd.apply("", args), "empty string");
+assert.throws(TypeError, () => dateAdd.apply(Symbol(), args), "symbol");
+assert.throws(TypeError, () => dateAdd.apply(1, args), "1");
+assert.throws(TypeError, () => dateAdd.apply({}, args), "plain object");
+assert.throws(TypeError, () => dateAdd.apply(Temporal.Calendar, args), "Temporal.Calendar");
+assert.throws(TypeError, () => dateAdd.apply(Temporal.Calendar.prototype, args), "Temporal.Calendar.prototype");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/browser.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/browser.js
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/builtin.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/builtin.js
new file mode 100644
index 0000000000..37351aff5a
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/builtin.js
@@ -0,0 +1,36 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: >
+ Tests that Temporal.Calendar.prototype.dateAdd
+ meets the requirements for built-in objects defined by the
+ introduction of chapter 17 of the ECMAScript Language Specification.
+info: |
+ Built-in functions that are not constructors do not have a "prototype" property unless
+ otherwise specified in the description of a particular function.
+
+ Unless specified otherwise, a built-in object that is callable as a function is a built-in
+ function object with the characteristics described in 10.3. Unless specified otherwise, the
+ [[Extensible]] internal slot of a built-in object initially has the value true.
+
+ Unless otherwise specified every built-in function and every built-in constructor has the
+ Function prototype object [...] as the value of its [[Prototype]] internal slot.
+features: [Temporal]
+---*/
+
+assert.sameValue(Object.isExtensible(Temporal.Calendar.prototype.dateAdd),
+ true, "Built-in objects must be extensible.");
+
+assert.sameValue(Object.prototype.toString.call(Temporal.Calendar.prototype.dateAdd),
+ "[object Function]", "Object.prototype.toString");
+
+assert.sameValue(Object.getPrototypeOf(Temporal.Calendar.prototype.dateAdd),
+ Function.prototype, "prototype");
+
+assert.sameValue(Temporal.Calendar.prototype.dateAdd.hasOwnProperty("prototype"),
+ false, "prototype property");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/calendar-datefromfields-called-with-options-undefined.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/calendar-datefromfields-called-with-options-undefined.js
new file mode 100644
index 0000000000..bfad861fe3
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/calendar-datefromfields-called-with-options-undefined.js
@@ -0,0 +1,18 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: >
+ Calendar.dateFromFields method is called with undefined as the options value
+ when call originates internally
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions();
+calendar.dateAdd({ year: 2000, month: 5, day: 2, calendar }, new Temporal.Duration(1));
+assert.sameValue(calendar.dateFromFieldsCallCount, 1);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/calendar-fields-iterable.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/calendar-fields-iterable.js
new file mode 100644
index 0000000000..b644d3e992
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/calendar-fields-iterable.js
@@ -0,0 +1,36 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: Verify the result of calendar.fields() is treated correctly.
+info: |
+ sec-temporal.calendar.prototype.dateadd step 4:
+ 4. Set _date_ to ? ToTemporalDate(_date_).
+ sec-temporal-totemporaldate step 2.c:
+ c. Let _fieldNames_ be ? CalendarFields(_calendar_, « *"day"*, *"month"*, *"monthCode"*, *"year"* »).
+ sec-temporal-calendarfields step 4:
+ 4. Let _result_ be ? IterableToListOfType(_fieldsArray_, « String »).
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const expected = [
+ "day",
+ "month",
+ "monthCode",
+ "year",
+];
+
+const duration = new Temporal.Duration(0, 1);
+const calendar1 = TemporalHelpers.calendarFieldsIterable();
+const calendar2 = TemporalHelpers.calendarFieldsIterable();
+calendar1.dateAdd({ year: 2000, month: 5, day: 2, calendar: calendar2 }, duration);
+
+assert.sameValue(calendar1.fieldsCallCount, 0, "fields() method not called");
+assert.sameValue(calendar2.fieldsCallCount, 1, "fields() method called once");
+assert.compareArray(calendar2.fieldsCalledWith[0], expected, "fields() method called with correct args");
+assert(calendar2.iteratorExhausted[0], "iterated through the whole iterable");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/calendar-temporal-object.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/calendar-temporal-object.js
new file mode 100644
index 0000000000..44ba8d6c9a
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/calendar-temporal-object.js
@@ -0,0 +1,30 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: Fast path for converting other Temporal objects to Temporal.Calendar by reading internal slots
+info: |
+ sec-temporal.calendar.prototype.dateadd step 4:
+ 4. Set _date_ to ? ToTemporalDate(_date_).
+ sec-temporal-totemporaldate step 2.c:
+ c. Let _calendar_ be ? GetTemporalCalendarWithISODefault(_item_).
+ sec-temporal-gettemporalcalendarwithisodefault step 2:
+ 2. Return ? ToTemporalCalendarWithISODefault(_calendar_).
+ sec-temporal-totemporalcalendarwithisodefault step 2:
+ 3. Return ? ToTemporalCalendar(_temporalCalendarLike_).
+ sec-temporal-totemporalcalendar step 1.a:
+ a. If _temporalCalendarLike_ has an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]], [[InitializedTemporalMonthDay]], [[InitializedTemporalYearMonth]], or [[InitializedTemporalZonedDateTime]] internal slot, then
+ i. Return _temporalCalendarLike_.[[Calendar]].
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+TemporalHelpers.checkToTemporalCalendarFastPath((temporalObject) => {
+ const calendar = new Temporal.Calendar("iso8601");
+ const duration = new Temporal.Duration(0, 1);
+ calendar.dateAdd({ year: 2000, month: 5, day: 2, calendar: temporalObject }, duration);
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/date-infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/date-infinity-throws-rangeerror.js
new file mode 100644
index 0000000000..c3ef141dc7
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/date-infinity-throws-rangeerror.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: Throws if any value in the property bag is Infinity or -Infinity
+esid: sec-temporal.calendar.prototype.dateadd
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+const duration = new Temporal.Duration(1);
+const base = { year: 2000, month: 5, day: 2 };
+
+[Infinity, -Infinity].forEach((inf) => {
+ ["year", "month", "day"].forEach((prop) => {
+ ["constrain", "reject"].forEach((overflow) => {
+ assert.throws(RangeError, () => instance.dateAdd({ ...base, [prop]: inf }, duration, { overflow }), `${prop} property cannot be ${inf} (overflow ${overflow}`);
+
+ const calls = [];
+ const obj = TemporalHelpers.toPrimitiveObserver(calls, inf, prop);
+ assert.throws(RangeError, () => instance.dateAdd({ ...base, [prop]: obj }, duration, { overflow }));
+ assert.compareArray(calls, [`get ${prop}.valueOf`, `call ${prop}.valueOf`], "it fails after fetching the primitive value");
+ });
+ });
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/duration-argument-string-negative-fractional-units.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/duration-argument-string-negative-fractional-units.js
new file mode 100644
index 0000000000..e1b7dd7116
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/duration-argument-string-negative-fractional-units.js
@@ -0,0 +1,21 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: Strings with fractional duration units are treated with the correct sign
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = new Temporal.Calendar("iso8601");
+const instance = new Temporal.PlainDate(2000, 5, 2, calendar);
+
+const resultHours = calendar.dateAdd(instance, "-PT24.567890123H");
+TemporalHelpers.assertPlainDate(resultHours, 2000, 5, "M05", 1, "negative fractional hours");
+
+const resultMinutes = calendar.dateAdd(instance, "-PT1440.567890123M");
+TemporalHelpers.assertPlainDate(resultMinutes, 2000, 5, "M05", 1, "negative fractional minutes");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/length.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/length.js
new file mode 100644
index 0000000000..4e13716808
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/length.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2020 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: Temporal.Calendar.prototype.dateAdd.length is 2
+info: |
+ Every built-in function object, including constructors, has a "length" property whose value is
+ an integer. Unless otherwise specified, this value is equal to the largest number of named
+ arguments shown in the subclause headings for the function description. Optional parameters
+ (which are indicated with brackets: [ ]) or rest parameters (which are shown using the form
+ «...name») are not included in the default argument count.
+
+ Unless otherwise specified, the "length" property of a built-in function object has the
+ attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+verifyProperty(Temporal.Calendar.prototype.dateAdd, "length", {
+ value: 2,
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/name.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/name.js
new file mode 100644
index 0000000000..e32dfcf838
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/name.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: Temporal.Calendar.prototype.dateAdd.name is "dateAdd".
+info: |
+ Every built-in function object, including constructors, that is not identified as an anonymous
+ function has a "name" property whose value is a String. Unless otherwise specified, this value
+ is the name that is given to the function in this specification.
+
+ Unless otherwise specified, the "name" property of a built-in function object, if it exists,
+ has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+verifyProperty(Temporal.Calendar.prototype.dateAdd, "name", {
+ value: "dateAdd",
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/not-a-constructor.js
new file mode 100644
index 0000000000..714fc59932
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/not-a-constructor.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: >
+ Temporal.Calendar.prototype.dateAdd does not implement [[Construct]], is not new-able
+info: |
+ Built-in function objects that are not identified as constructors do not implement the
+ [[Construct]] internal method unless otherwise specified in the description of a particular
+ function.
+includes: [isConstructor.js]
+features: [Reflect.construct, Temporal]
+---*/
+
+assert.throws(TypeError, () => {
+ new Temporal.Calendar.prototype.dateAdd();
+}, "Calling as constructor");
+
+assert.sameValue(isConstructor(Temporal.Calendar.prototype.dateAdd), false,
+ "isConstructor(Temporal.Calendar.prototype.dateAdd)");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/options-object.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/options-object.js
new file mode 100644
index 0000000000..5e083cbdf4
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/options-object.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: Empty or a function object may be used as options
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const result1 = instance.dateAdd(new Temporal.PlainDate(1976, 11, 18), new Temporal.Duration(1), {});
+TemporalHelpers.assertPlainDate(
+ result1, 1977, 11, "M11", 18,
+ "options may be an empty plain object"
+);
+
+const result2 = instance.dateAdd(new Temporal.PlainDate(1976, 11, 18), new Temporal.Duration(1), () => {});
+TemporalHelpers.assertPlainDate(
+ result2, 1977, 11, "M11", 18,
+ "options may be a function object"
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/options-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/options-wrong-type.js
new file mode 100644
index 0000000000..68f08ff73a
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/options-wrong-type.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: TypeError thrown when options argument is a primitive
+features: [BigInt, Symbol, Temporal]
+---*/
+
+const badOptions = [
+ null,
+ true,
+ "some string",
+ Symbol(),
+ 1,
+ 2n,
+];
+
+const instance = new Temporal.Calendar("iso8601");
+for (const value of badOptions) {
+ assert.throws(TypeError, () => instance.dateAdd(new Temporal.PlainDate(1976, 11, 18), new Temporal.Duration(1), value),
+ `TypeError on wrong options type ${typeof value}`);
+};
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/order-of-operations.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/order-of-operations.js
new file mode 100644
index 0000000000..c1a3409489
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/order-of-operations.js
@@ -0,0 +1,122 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: Properties on an object passed to dateAdd() are accessed in the correct order
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const expected = [
+ // ToTemporalDate → GetTemporalCalendarSlotValueWithISODefault
+ "get date.calendar",
+ "has date.calendar.dateAdd",
+ "has date.calendar.dateFromFields",
+ "has date.calendar.dateUntil",
+ "has date.calendar.day",
+ "has date.calendar.dayOfWeek",
+ "has date.calendar.dayOfYear",
+ "has date.calendar.daysInMonth",
+ "has date.calendar.daysInWeek",
+ "has date.calendar.daysInYear",
+ "has date.calendar.fields",
+ "has date.calendar.id",
+ "has date.calendar.inLeapYear",
+ "has date.calendar.mergeFields",
+ "has date.calendar.month",
+ "has date.calendar.monthCode",
+ "has date.calendar.monthDayFromFields",
+ "has date.calendar.monthsInYear",
+ "has date.calendar.weekOfYear",
+ "has date.calendar.year",
+ "has date.calendar.yearMonthFromFields",
+ "has date.calendar.yearOfWeek",
+ // lookup
+ "get date.calendar.dateFromFields",
+ "get date.calendar.fields",
+ // ToTemporalDate → CalendarFields
+ "call date.calendar.fields",
+ // ToTemporalDate → PrepareTemporalFields
+ "get date.day",
+ "get date.day.valueOf",
+ "call date.day.valueOf",
+ "get date.month",
+ "get date.month.valueOf",
+ "call date.month.valueOf",
+ "get date.monthCode",
+ "get date.monthCode.toString",
+ "call date.monthCode.toString",
+ "get date.year",
+ "get date.year.valueOf",
+ "call date.year.valueOf",
+ // ToTemporalDate → CalendarDateFromFields
+ "call date.calendar.dateFromFields",
+ // ToTemporalDuration
+ "get duration.days",
+ "get duration.days.valueOf",
+ "call duration.days.valueOf",
+ "get duration.hours",
+ "get duration.hours.valueOf",
+ "call duration.hours.valueOf",
+ "get duration.microseconds",
+ "get duration.microseconds.valueOf",
+ "call duration.microseconds.valueOf",
+ "get duration.milliseconds",
+ "get duration.milliseconds.valueOf",
+ "call duration.milliseconds.valueOf",
+ "get duration.minutes",
+ "get duration.minutes.valueOf",
+ "call duration.minutes.valueOf",
+ "get duration.months",
+ "get duration.months.valueOf",
+ "call duration.months.valueOf",
+ "get duration.nanoseconds",
+ "get duration.nanoseconds.valueOf",
+ "call duration.nanoseconds.valueOf",
+ "get duration.seconds",
+ "get duration.seconds.valueOf",
+ "call duration.seconds.valueOf",
+ "get duration.weeks",
+ "get duration.weeks.valueOf",
+ "call duration.weeks.valueOf",
+ "get duration.years",
+ "get duration.years.valueOf",
+ "call duration.years.valueOf",
+ // ToTemporalOverflow
+ "get options.overflow",
+ "get options.overflow.toString",
+ "call options.overflow.toString",
+];
+const actual = [];
+
+const instance = new Temporal.Calendar("iso8601");
+
+const date = TemporalHelpers.propertyBagObserver(actual, {
+ year: 2000,
+ month: 5,
+ monthCode: "M05",
+ day: 2,
+ calendar: TemporalHelpers.calendarObserver(actual, "date.calendar"),
+}, "date");
+
+const duration = TemporalHelpers.propertyBagObserver(actual, {
+ years: 1,
+ months: 2,
+ weeks: 3,
+ days: 4,
+ hours: 5,
+ minutes: 6,
+ seconds: 7,
+ milliseconds: 8,
+ microseconds: 9,
+ nanoseconds: 10,
+}, "duration");
+
+const options = TemporalHelpers.propertyBagObserver(actual, { overflow: "constrain" }, "options");
+
+instance.dateAdd(date, duration, options);
+assert.compareArray(actual, expected, "order of operations");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/overflow-invalid-string.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/overflow-invalid-string.js
new file mode 100644
index 0000000000..fe288222f2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/overflow-invalid-string.js
@@ -0,0 +1,30 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: RangeError thrown when overflow option not one of the allowed string values
+info: |
+ sec-getoption step 10:
+ 10. If _values_ is not *undefined* and _values_ does not contain an element equal to _value_, throw a *RangeError* exception.
+ sec-temporal-totemporaloverflow step 1:
+ 1. Return ? GetOption(_normalizedOptions_, *"overflow"*, « String », « *"constrain"*, *"reject"* », *"constrain"*).
+ sec-temporal.calendar.prototype.dateadd step 7:
+ 7. Let _overflow_ be ? ToTemporalOverflow(_options_).
+features: [Temporal, arrow-function]
+---*/
+
+const calendar = new Temporal.Calendar("iso8601");
+const date = new Temporal.PlainDate(2000, 5, 2, calendar);
+const duration = new Temporal.Duration(3, 3, 0, 3);
+const badOverflows = ["", "CONSTRAIN", "balance", "other string", "constra\u0131n", "reject\0"];
+for (const overflow of badOverflows) {
+ assert.throws(
+ RangeError,
+ () => calendar.dateAdd(date, duration, { overflow }),
+ `invalid overflow ("${overflow}")`
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/overflow-undefined.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/overflow-undefined.js
new file mode 100644
index 0000000000..83728adf8c
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/overflow-undefined.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: Fallback value for overflow option
+info: |
+ sec-getoption step 3:
+ 3. If _value_ is *undefined*, return _fallback_.
+ sec-temporal-totemporaloverflow step 1:
+ 1. Return ? GetOption(_normalizedOptions_, *"overflow"*, « String », « *"constrain"*, *"reject"* », *"constrain"*).
+ sec-temporal.calendar.prototype.dateadd step 7:
+ 7. Let _overflow_ be ? ToTemporalOverflow(_options_).
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = new Temporal.Calendar("iso8601");
+const date = new Temporal.PlainDate(2000, 5, 31, calendar);
+const duration = new Temporal.Duration(3, 1);
+
+const explicit = calendar.dateAdd(date, duration, { overflow: undefined });
+TemporalHelpers.assertPlainDate(explicit, 2003, 6, "M06", 30, "default overflow is constrain");
+const implicit = calendar.dateAdd(date, duration, {});
+TemporalHelpers.assertPlainDate(implicit, 2003, 6, "M06", 30, "default overflow is constrain");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/overflow-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/overflow-wrong-type.js
new file mode 100644
index 0000000000..48da48d4a3
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/overflow-wrong-type.js
@@ -0,0 +1,27 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: Type conversions for overflow option
+info: |
+ sec-getoption step 9.a:
+ a. Set _value_ to ? ToString(_value_).
+ sec-temporal-totemporaloverflow step 1:
+ 1. Return ? GetOption(_normalizedOptions_, *"overflow"*, « String », « *"constrain"*, *"reject"* », *"constrain"*).
+ sec-temporal.calendar.prototype.dateadd step 7:
+ 7. Let _overflow_ be ? ToTemporalOverflow(_options_).
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = new Temporal.Calendar("iso8601");
+const date = new Temporal.PlainDate(2000, 5, 2, calendar);
+const duration = new Temporal.Duration(3, 3, 0, 3);
+TemporalHelpers.checkStringOptionWrongType("overflow", "constrain",
+ (overflow) => calendar.dateAdd(date, duration, { overflow }),
+ (result, descr) => TemporalHelpers.assertPlainDate(result, 2003, 8, "M08", 5, descr),
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/prop-desc.js
new file mode 100644
index 0000000000..72ef97adf8
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/prop-desc.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: The "dateAdd" property of Temporal.Calendar.prototype
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+assert.sameValue(
+ typeof Temporal.Calendar.prototype.dateAdd,
+ "function",
+ "`typeof Calendar.prototype.dateAdd` is `function`"
+);
+
+verifyProperty(Temporal.Calendar.prototype, "dateAdd", {
+ writable: true,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/shell.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/shell.js
new file mode 100644
index 0000000000..eda1477282
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/shell.js
@@ -0,0 +1,24 @@
+// GENERATED, DO NOT EDIT
+// file: isConstructor.js
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: |
+ Test if a given function is a constructor function.
+defines: [isConstructor]
+features: [Reflect.construct]
+---*/
+
+function isConstructor(f) {
+ if (typeof f !== "function") {
+ throw new Test262Error("isConstructor invoked with a non-function value");
+ }
+
+ try {
+ Reflect.construct(function(){}, [], f);
+ } catch (e) {
+ return false;
+ }
+ return true;
+}
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/throw-range-error-from-ToTemporalDate.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/throw-range-error-from-ToTemporalDate.js
new file mode 100644
index 0000000000..9292f126ad
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/throw-range-error-from-ToTemporalDate.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: Temporal.Calendar.prototype.dateAdd should throw from ToTemporalDate.
+info: |
+ ...
+ 4. Set date to ? ToTemporalDate(date).
+features: [Temporal, arrow-function]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+assert.throws(RangeError,
+ () => cal.dateAdd("invalid date string", new Temporal.Duration(1)),
+ 'cal.dateAdd("invalid date string", new Temporal.Duration(1)) throws a RangeError exception');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/throw-range-error-from-ToTemporalDuration.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/throw-range-error-from-ToTemporalDuration.js
new file mode 100644
index 0000000000..4c4ae43502
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/throw-range-error-from-ToTemporalDuration.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: Temporal.Calendar.prototype.dateAdd should throw from ToTemporalDuration.
+info: |
+ ...
+ 5. Set duration to ? ToTemporalDuration(duration).
+features: [Temporal, arrow-function]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+assert.throws(RangeError,
+ () => cal.dateAdd("2020-02-03", "invalid duration string"),
+ 'cal.dateAdd("2020-02-03", "invalid duration string") throws a RangeError exception');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/throw-type-error-from-GetOptionsObject.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/throw-type-error-from-GetOptionsObject.js
new file mode 100644
index 0000000000..c0a83de563
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/throw-type-error-from-GetOptionsObject.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: Temporal.Calendar.prototype.dateAdd should throw from GetOptionsObject.
+info: |
+ ...
+ 6. Set options to ? GetOptionsObject(options).
+features: [BigInt, Symbol, Temporal, arrow-function]
+---*/
+let cal = new Temporal.Calendar('iso8601');
+let invalidOptionsList = [null, 'invalid option', 234, 23n, Symbol('foo'), true, false, Infinity];
+
+invalidOptionsList.forEach(function(invalidOptions) {
+ assert.throws(
+ TypeError,
+ () => cal.dateAdd('2020-02-03', 'P1Y', invalidOptions),
+ 'cal.dateAdd("2020-02-03", "P1Y", invalidOptions) throws a TypeError exception'
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/year-zero.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/year-zero.js
new file mode 100644
index 0000000000..4d9c53e388
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateAdd/year-zero.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateadd
+description: Negative zero, as an extended year, is rejected
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ "-000000-10-31",
+ "-000000-10-31T00:45",
+ "-000000-10-31T00:45+01:00",
+ "-000000-10-31T00:45+00:00[UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.dateAdd(arg, new Temporal.Duration()),
+ "reject minus zero as extended year"
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/branding.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/branding.js
new file mode 100644
index 0000000000..6758e0cdd1
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/branding.js
@@ -0,0 +1,27 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.datefromfields
+description: Throw a TypeError if the receiver is invalid
+features: [Symbol, Temporal]
+---*/
+
+const dateFromFields = Temporal.Calendar.prototype.dateFromFields;
+
+assert.sameValue(typeof dateFromFields, "function");
+
+const args = [{ year: 2000, month: 1, day: 1 }];
+
+assert.throws(TypeError, () => dateFromFields.apply(undefined, args), "undefined");
+assert.throws(TypeError, () => dateFromFields.apply(null, args), "null");
+assert.throws(TypeError, () => dateFromFields.apply(true, args), "true");
+assert.throws(TypeError, () => dateFromFields.apply("", args), "empty string");
+assert.throws(TypeError, () => dateFromFields.apply(Symbol(), args), "symbol");
+assert.throws(TypeError, () => dateFromFields.apply(1, args), "1");
+assert.throws(TypeError, () => dateFromFields.apply({}, args), "plain object");
+assert.throws(TypeError, () => dateFromFields.apply(Temporal.Calendar, args), "Temporal.Calendar");
+assert.throws(TypeError, () => dateFromFields.apply(Temporal.Calendar.prototype, args), "Temporal.Calendar.prototype");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/browser.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/browser.js
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/builtin.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/builtin.js
new file mode 100644
index 0000000000..f039b1d2cd
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/builtin.js
@@ -0,0 +1,36 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.datefromfields
+description: >
+ Tests that Temporal.Calendar.prototype.dateFromFields
+ meets the requirements for built-in objects defined by the
+ introduction of chapter 17 of the ECMAScript Language Specification.
+info: |
+ Built-in functions that are not constructors do not have a "prototype" property unless
+ otherwise specified in the description of a particular function.
+
+ Unless specified otherwise, a built-in object that is callable as a function is a built-in
+ function object with the characteristics described in 10.3. Unless specified otherwise, the
+ [[Extensible]] internal slot of a built-in object initially has the value true.
+
+ Unless otherwise specified every built-in function and every built-in constructor has the
+ Function prototype object [...] as the value of its [[Prototype]] internal slot.
+features: [Temporal]
+---*/
+
+assert.sameValue(Object.isExtensible(Temporal.Calendar.prototype.dateFromFields),
+ true, "Built-in objects must be extensible.");
+
+assert.sameValue(Object.prototype.toString.call(Temporal.Calendar.prototype.dateFromFields),
+ "[object Function]", "Object.prototype.toString");
+
+assert.sameValue(Object.getPrototypeOf(Temporal.Calendar.prototype.dateFromFields),
+ Function.prototype, "prototype");
+
+assert.sameValue(Temporal.Calendar.prototype.dateFromFields.hasOwnProperty("prototype"),
+ false, "prototype property");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/fields-not-object.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/fields-not-object.js
new file mode 100644
index 0000000000..38475bb330
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/fields-not-object.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.datefromfields
+description: Throw a TypeError if the fields is not an object
+info: |
+ 4. If Type(_fields_) is not Object, throw a *TypeError* exception.
+features: [BigInt, Symbol, Temporal, arrow-function]
+---*/
+
+const tests = [undefined, null, true, false, "string", Symbol("sym"), Infinity, NaN, Math.PI, 42n];
+const iso = Temporal.Calendar.from("iso8601");
+for (const fields of tests) {
+ assert.throws(
+ TypeError,
+ () => iso.dateFromFields(fields, {})
+ `dateFromFields(${typeof fields}) throws a TypeError exception`
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/infinity-throws-rangeerror.js
new file mode 100644
index 0000000000..3024c6466b
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/infinity-throws-rangeerror.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: Throws if any value in the property bag is Infinity or -Infinity
+esid: sec-temporal.calendar.prototype.datefromfields
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+const base = { year: 2000, month: 5, day: 2 };
+
+[Infinity, -Infinity].forEach((inf) => {
+ ["year", "month", "day"].forEach((prop) => {
+ ["constrain", "reject"].forEach((overflow) => {
+ assert.throws(RangeError, () => instance.dateFromFields({ ...base, [prop]: inf }, { overflow }), `${prop} property cannot be ${inf} (overflow ${overflow}`);
+
+ const calls = [];
+ const obj = TemporalHelpers.toPrimitiveObserver(calls, inf, prop);
+ assert.throws(RangeError, () => instance.dateFromFields({ ...base, [prop]: obj }, { overflow }));
+ assert.compareArray(calls, [`get ${prop}.valueOf`, `call ${prop}.valueOf`], "it fails after fetching the primitive value");
+ });
+ });
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/length.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/length.js
new file mode 100644
index 0000000000..3c7ec630d9
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/length.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2020 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.datefromfields
+description: Temporal.Calendar.prototype.dateFromFields.length is 1
+info: |
+ Every built-in function object, including constructors, has a "length" property whose value is
+ an integer. Unless otherwise specified, this value is equal to the largest number of named
+ arguments shown in the subclause headings for the function description. Optional parameters
+ (which are indicated with brackets: [ ]) or rest parameters (which are shown using the form
+ «...name») are not included in the default argument count.
+
+ Unless otherwise specified, the "length" property of a built-in function object has the
+ attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+verifyProperty(Temporal.Calendar.prototype.dateFromFields, "length", {
+ value: 1,
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/missing-properties.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/missing-properties.js
new file mode 100644
index 0000000000..6a9ffd5dfc
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/missing-properties.js
@@ -0,0 +1,48 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.datefromfields
+description: Errors due to missing properties on fields object are thrown in the correct order
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const missingDay = {
+ get year() {
+ TemporalHelpers.assertUnreachable("day should be checked first");
+ },
+ get month() {
+ TemporalHelpers.assertUnreachable("day should be checked first");
+ },
+ get monthCode() {
+ TemporalHelpers.assertUnreachable("day should be checked first");
+ },
+};
+assert.throws(TypeError, () => instance.dateFromFields(missingDay), "day should be checked before year and month");
+
+let getMonth = false;
+let getMonthCode = false;
+const missingYearAndMonth = {
+ day: 1,
+ get month() {
+ getMonth = true;
+ },
+ get monthCode() {
+ getMonthCode = true;
+ },
+};
+assert.throws(TypeError, () => instance.dateFromFields(missingYearAndMonth), "year should be checked after fetching but before resolving the month");
+assert(getMonth, "year is fetched after month");
+assert(getMonthCode, "year is fetched after monthCode");
+
+const missingMonth = {
+ day: 1,
+ year: 2000,
+};
+assert.throws(TypeError, () => instance.dateFromFields(missingMonth), "month should be resolved last");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/name.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/name.js
new file mode 100644
index 0000000000..f88fb05139
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/name.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.datefromfields
+description: Temporal.Calendar.prototype.dateFromFields.name is "dateFromFields".
+info: |
+ Every built-in function object, including constructors, that is not identified as an anonymous
+ function has a "name" property whose value is a String. Unless otherwise specified, this value
+ is the name that is given to the function in this specification.
+
+ Unless otherwise specified, the "name" property of a built-in function object, if it exists,
+ has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+verifyProperty(Temporal.Calendar.prototype.dateFromFields, "name", {
+ value: "dateFromFields",
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/not-a-constructor.js
new file mode 100644
index 0000000000..bc9a9a78c2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/not-a-constructor.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.datefromfields
+description: >
+ Temporal.Calendar.prototype.dateFromFields does not implement [[Construct]], is not new-able
+info: |
+ Built-in function objects that are not identified as constructors do not implement the
+ [[Construct]] internal method unless otherwise specified in the description of a particular
+ function.
+includes: [isConstructor.js]
+features: [Reflect.construct, Temporal]
+---*/
+
+assert.throws(TypeError, () => {
+ new Temporal.Calendar.prototype.dateFromFields();
+}, "Calling as constructor");
+
+assert.sameValue(isConstructor(Temporal.Calendar.prototype.dateFromFields), false,
+ "isConstructor(Temporal.Calendar.prototype.dateFromFields)");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/one-of-era-erayear-undefined.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/one-of-era-erayear-undefined.js
new file mode 100644
index 0000000000..67d4befdce
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/one-of-era-erayear-undefined.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.datefromfields
+description: Does not throw a RangeError if only one of era/eraYear fields is present
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+const base = { year: 2000, month: 5, day: 2, era: 'ce' };
+const instance = new Temporal.Calendar('iso8601');
+TemporalHelpers.assertPlainDate(instance.dateFromFields({ ...base }), 2000, 5, 'M05', 2);
+
+const base2 = { year: 2000, month: 5, day: 2, eraYear: 1 };
+TemporalHelpers.assertPlainDate(instance.dateFromFields({ ...base }), 2000, 5, 'M05', 2);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/options-object.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/options-object.js
new file mode 100644
index 0000000000..2905c8ea94
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/options-object.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.datefromfields
+description: Empty or a function object may be used as options
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const result1 = instance.dateFromFields({ year: 1976, month: 11, day: 18 }, {});
+TemporalHelpers.assertPlainDate(
+ result1, 1976, 11, "M11", 18,
+ "options may be an empty plain object"
+);
+
+const result2 = instance.dateFromFields({ year: 1976, month: 11, day: 18 }, () => {});
+TemporalHelpers.assertPlainDate(
+ result2, 1976, 11, "M11", 18,
+ "options may be a function object"
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/options-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/options-wrong-type.js
new file mode 100644
index 0000000000..9193330fdd
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/options-wrong-type.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.datefromfields
+description: TypeError thrown when options argument is a primitive
+features: [BigInt, Symbol, Temporal]
+---*/
+
+const badOptions = [
+ null,
+ true,
+ "some string",
+ Symbol(),
+ 1,
+ 2n,
+];
+
+const instance = new Temporal.Calendar("iso8601");
+for (const value of badOptions) {
+ assert.throws(TypeError, () => instance.dateFromFields({ year: 1976, month: 11, day: 18 }, value),
+ `TypeError on wrong options type ${typeof value}`);
+};
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/order-of-operations.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/order-of-operations.js
new file mode 100644
index 0000000000..aff7bbdde3
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/order-of-operations.js
@@ -0,0 +1,49 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.datefromfields
+description: Properties on objects passed to dateFromFields() are accessed in the correct order
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const expected = [
+ "get fields.day",
+ "get fields.day.valueOf",
+ "call fields.day.valueOf",
+ "get fields.month",
+ "get fields.month.valueOf",
+ "call fields.month.valueOf",
+ "get fields.monthCode",
+ "get fields.monthCode.toString",
+ "call fields.monthCode.toString",
+ "get fields.year",
+ "get fields.year.valueOf",
+ "call fields.year.valueOf",
+ "get options.overflow",
+ "get options.overflow.toString",
+ "call options.overflow.toString",
+];
+const actual = [];
+
+const instance = new Temporal.Calendar("iso8601");
+
+const fields = TemporalHelpers.propertyBagObserver(actual, {
+ year: 1.7,
+ month: 1.7,
+ monthCode: "M01",
+ day: 1.7,
+}, "fields");
+
+const options = TemporalHelpers.propertyBagObserver(actual, {
+ overflow: "reject",
+}, "options");
+
+const result = instance.dateFromFields(fields, options);
+TemporalHelpers.assertPlainDate(result, 1, 1, "M01", 1, "date result");
+assert.sameValue(result.getISOFields().calendar, "iso8601", "calendar slot should store a string");
+assert.compareArray(actual, expected, "order of operations");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/overflow-invalid-string.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/overflow-invalid-string.js
new file mode 100644
index 0000000000..153e0361c2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/overflow-invalid-string.js
@@ -0,0 +1,31 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.datefromfields
+description: RangeError thrown when overflow option not one of the allowed string values
+info: |
+ sec-getoption step 10:
+ 10. If _values_ is not *undefined* and _values_ does not contain an element equal to _value_, throw a *RangeError* exception.
+ sec-temporal-totemporaloverflow step 1:
+ 1. Return ? GetOption(_normalizedOptions_, *"overflow"*, « String », « *"constrain"*, *"reject"* », *"constrain"*).
+ sec-temporal-isodatefromfields step 2:
+ 2. Let _overflow_ be ? ToTemporalOverflow(_options_).
+ sec-temporal.calendar.prototype.datefromfields step 6:
+ 6. Let _result_ be ? ISODateFromFields(_fields_, _options_).
+features: [Temporal, arrow-function]
+---*/
+
+const calendar = new Temporal.Calendar("iso8601");
+const badOverflows = ["", "CONSTRAIN", "balance", "other string", "constra\u0131n", "reject\0"];
+for (const overflow of badOverflows) {
+ assert.throws(
+ RangeError,
+ () => calendar.dateFromFields({ year: 2000, month: 5, day: 2 },
+ { overflow }),
+ `invalid overflow ("${overflow}")`
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/overflow-undefined.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/overflow-undefined.js
new file mode 100644
index 0000000000..3e4b9bb1d9
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/overflow-undefined.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.datefromfields
+description: Fallback value for overflow option
+info: |
+ sec-getoption step 3:
+ 3. If _value_ is *undefined*, return _fallback_.
+ sec-temporal-totemporaloverflow step 1:
+ 1. Return ? GetOption(_normalizedOptions_, *"overflow"*, « String », « *"constrain"*, *"reject"* », *"constrain"*).
+ sec-temporal-isodatefromfields step 2:
+ 2. Let _overflow_ be ? ToTemporalOverflow(_options_).
+ sec-temporal.calendar.prototype.datefromfields step 6:
+ 6. Let _result_ be ? ISODateFromFields(_fields_, _options_).
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = new Temporal.Calendar("iso8601");
+
+const explicit = calendar.dateFromFields({ year: 2000, month: 15, day: 2 }, { overflow: undefined });
+TemporalHelpers.assertPlainDate(explicit, 2000, 12, "M12", 2, "default overflow is constrain");
+const implicit = calendar.dateFromFields({ year: 2000, month: 15, day: 2 }, {});
+TemporalHelpers.assertPlainDate(implicit, 2000, 12, "M12", 2, "default overflow is constrain");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/overflow-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/overflow-wrong-type.js
new file mode 100644
index 0000000000..b75d4beb59
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/overflow-wrong-type.js
@@ -0,0 +1,27 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.datefromfields
+description: Type conversions for overflow option
+info: |
+ sec-getoption step 9.a:
+ a. Set _value_ to ? ToString(_value_).
+ sec-temporal-totemporaloverflow step 1:
+ 1. Return ? GetOption(_normalizedOptions_, *"overflow"*, « String », « *"constrain"*, *"reject"* », *"constrain"*).
+ sec-temporal-isodatefromfields step 2:
+ 2. Let _overflow_ be ? ToTemporalOverflow(_options_).
+ sec-temporal.calendar.prototype.datefromfields step 6:
+ 6. Let _result_ be ? ISODateFromFields(_fields_, _options_).
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = new Temporal.Calendar("iso8601");
+TemporalHelpers.checkStringOptionWrongType("overflow", "constrain",
+ (overflow) => calendar.dateFromFields({ year: 2000, month: 5, day: 2 }, { overflow }),
+ (result, descr) => TemporalHelpers.assertPlainDate(result, 2000, 5, "M05", 2, descr),
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/prop-desc.js
new file mode 100644
index 0000000000..50871e8d91
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/prop-desc.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.datefromfields
+description: The "dateFromFields" property of Temporal.Calendar.prototype
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+assert.sameValue(
+ typeof Temporal.Calendar.prototype.dateFromFields,
+ "function",
+ "`typeof Calendar.prototype.dateFromFields` is `function`"
+);
+
+verifyProperty(Temporal.Calendar.prototype, "dateFromFields", {
+ writable: true,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/shell.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/shell.js
new file mode 100644
index 0000000000..eda1477282
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/shell.js
@@ -0,0 +1,24 @@
+// GENERATED, DO NOT EDIT
+// file: isConstructor.js
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: |
+ Test if a given function is a constructor function.
+defines: [isConstructor]
+features: [Reflect.construct]
+---*/
+
+function isConstructor(f) {
+ if (typeof f !== "function") {
+ throw new Test262Error("isConstructor invoked with a non-function value");
+ }
+
+ try {
+ Reflect.construct(function(){}, [], f);
+ } catch (e) {
+ return false;
+ }
+ return true;
+}
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/throw-type-error-from-GetOptionsObject.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/throw-type-error-from-GetOptionsObject.js
new file mode 100644
index 0000000000..53393dae1e
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/throw-type-error-from-GetOptionsObject.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.datefromfields
+description: Temporal.Calendar.prototype.dateFromFields should throw TypeError from GetOptionsObject.
+info: |
+ 4. If Type(fields) is not Object, throw a TypeError exception.
+features: [BigInt, Symbol, Temporal, arrow-function]
+---*/
+let cal = new Temporal.Calendar('iso8601');
+
+let fields = {
+ year: 2021,
+ month: 7,
+ day: 20
+};
+
+let notObjectList = [null, 'string', Symbol('efg'), true, false, Infinity, NaN, 123, 456n];
+
+notObjectList.forEach(function(options) {
+ assert.throws(
+ TypeError,
+ () => cal.dateFromFields(fields, options),
+ 'cal.dateFromFields(fields, options) throws a TypeError exception'
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/throws-range-error.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/throws-range-error.js
new file mode 100644
index 0000000000..3b11f18888
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/throws-range-error.js
@@ -0,0 +1,126 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.datefromfields
+description: >
+ Temporal.Calendar.prototype.dateFromFields should throw RangeError for
+ input not in valid range.
+info: |
+ 1. Let calendar be the this value.
+ 2. Perform ? RequireInternalSlot(calendar, [[InitializedTemporalCalendar]]).
+ 3. Assert: calendar.[[Identifier]] is "iso8601".
+ 4. If Type(fields) is not Object, throw a TypeError exception.
+ 5. Set options to ? GetOptionsObject(options).
+ 6. Let result be ? ISODateFromFields(fields, options).
+ 7. Return ? CreateTemporalDate(result.[[Year]], result.[[Month]], result.[[Day]], calendar).
+features: [Temporal, arrow-function]
+---*/
+let cal = new Temporal.Calendar("iso8601")
+
+assert.throws(RangeError, () => cal.dateFromFields({year: 2021, monthCode: "m1", day: 17}),
+ 'cal.dateFromFields({year: 2021, monthCode: "m1", day: 17}) throws a RangeError exception');
+assert.throws(RangeError, () => cal.dateFromFields({year: 2021, monthCode: "M1", day: 17}),
+ 'cal.dateFromFields({year: 2021, monthCode: "M1", day: 17}) throws a RangeError exception');
+assert.throws(RangeError, () => cal.dateFromFields({year: 2021, monthCode: "m01", day: 17}),
+ 'cal.dateFromFields({year: 2021, monthCode: "m01", day: 17}) throws a RangeError exception');
+
+assert.throws(RangeError, () => cal.dateFromFields({year: 2021, month: 12, monthCode: "M11", day: 17}),
+ 'cal.dateFromFields({year: 2021, month: 12, monthCode: "M11", day: 17}) throws a RangeError exception');
+assert.throws(RangeError, () => cal.dateFromFields({year: 2021, monthCode: "M00", day: 17}),
+ 'cal.dateFromFields({year: 2021, monthCode: "M00", day: 17}) throws a RangeError exception');
+assert.throws(RangeError, () => cal.dateFromFields({year: 2021, monthCode: "M19", day: 17}),
+ 'cal.dateFromFields({year: 2021, monthCode: "M19", day: 17}) throws a RangeError exception');
+assert.throws(RangeError, () => cal.dateFromFields({year: 2021, monthCode: "M99", day: 17}),
+ 'cal.dateFromFields({year: 2021, monthCode: "M99", day: 17}) throws a RangeError exception');
+assert.throws(RangeError, () => cal.dateFromFields({year: 2021, monthCode: "M13", day: 17}),
+ 'cal.dateFromFields({year: 2021, monthCode: "M13", day: 17}) throws a RangeError exception');
+
+assert.throws(RangeError, () => cal.dateFromFields({year: 2021, month: -1, day: 17}),
+ 'cal.dateFromFields({year: 2021, month: -1, day: 17}) throws a RangeError exception');
+assert.throws(RangeError, () => cal.dateFromFields({year: 2021, month: -Infinity, day: 17}),
+ 'cal.dateFromFields({year: 2021, month: -Infinity, day: 17}) throws a RangeError exception');
+assert.throws(RangeError, () => cal.dateFromFields({year: 2021, month: 7, day: -17}),
+ 'cal.dateFromFields({year: 2021, month: 7, day: -17}) throws a RangeError exception');
+assert.throws(RangeError, () => cal.dateFromFields({year: 2021, month: 7, day: -Infinity}),
+ 'cal.dateFromFields({year: 2021, month: 7, day: -Infinity}) throws a RangeError exception');
+
+assert.throws(RangeError, () => cal.dateFromFields({year: 2021, month: 12, day: 0}, {overflow: "reject"}),
+ 'cal.dateFromFields({year: 2021, month: 12, day: 0}, {overflow: "reject"}) throws a RangeError exception');
+assert.throws(RangeError, () => cal.dateFromFields({year: 2021, month: 12, day: 32}, {overflow: "reject"}),
+ 'cal.dateFromFields({year: 2021, month: 12, day: 32}, {overflow: "reject"}) throws a RangeError exception');
+assert.throws(RangeError, () => cal.dateFromFields({year: 2021, month: 1, day: 32}, {overflow: "reject"}),
+ 'cal.dateFromFields({year: 2021, month: 1, day: 32}, {overflow: "reject"}) throws a RangeError exception');
+assert.throws(RangeError, () => cal.dateFromFields({year: 2021, month: 2, day: 29}, {overflow: "reject"}),
+ 'cal.dateFromFields({year: 2021, month: 2, day: 29}, {overflow: "reject"}) throws a RangeError exception');
+assert.throws(RangeError, () => cal.dateFromFields({year: 2021, month: 6, day: 31}, {overflow: "reject"}),
+ 'cal.dateFromFields({year: 2021, month: 6, day: 31}, {overflow: "reject"}) throws a RangeError exception');
+assert.throws(RangeError, () => cal.dateFromFields({year: 2021, month: 9, day: 31}, {overflow: "reject"}),
+ 'cal.dateFromFields({year: 2021, month: 9, day: 31}, {overflow: "reject"}) throws a RangeError exception');
+assert.throws(RangeError, () => cal.dateFromFields({year: 2021, month: 0, day: 5}, {overflow: "reject"}),
+ 'cal.dateFromFields({year: 2021, month: 0, day: 5}, {overflow: "reject"}) throws a RangeError exception');
+assert.throws(RangeError, () => cal.dateFromFields({year: 2021, month: 13, day: 5}, {overflow: "reject"}),
+ 'cal.dateFromFields({year: 2021, month: 13, day: 5}, {overflow: "reject"}) throws a RangeError exception');
+
+assert.throws(RangeError, () => cal.dateFromFields(
+ {year: 2021, monthCode: "M12", day: 0}, {overflow: "reject"}),
+ 'cal.dateFromFields( {year: 2021, monthCode: "M12", day: 0}, {overflow: "reject"}) throws a RangeError exception');
+assert.throws(RangeError, () => cal.dateFromFields(
+ {year: 2021, monthCode: "M12", day: 32}, {overflow: "reject"}),
+ 'cal.dateFromFields( {year: 2021, monthCode: "M12", day: 32}, {overflow: "reject"}) throws a RangeError exception');
+assert.throws(RangeError, () => cal.dateFromFields(
+ {year: 2021, monthCode: "M01", day: 32}, {overflow: "reject"}),
+ 'cal.dateFromFields( {year: 2021, monthCode: "M01", day: 32}, {overflow: "reject"}) throws a RangeError exception');
+assert.throws(RangeError, () => cal.dateFromFields(
+ {year: 2021, monthCode: "M02", day: 29}, {overflow: "reject"}),
+ 'cal.dateFromFields( {year: 2021, monthCode: "M02", day: 29}, {overflow: "reject"}) throws a RangeError exception');
+assert.throws(RangeError, () => cal.dateFromFields(
+ {year: 2021, monthCode: "M06", day: 31}, {overflow: "reject"}),
+ 'cal.dateFromFields( {year: 2021, monthCode: "M06", day: 31}, {overflow: "reject"}) throws a RangeError exception');
+assert.throws(RangeError, () => cal.dateFromFields(
+ {year: 2021, monthCode: "M09", day: 31}, {overflow: "reject"}),
+ 'cal.dateFromFields( {year: 2021, monthCode: "M09", day: 31}, {overflow: "reject"}) throws a RangeError exception');
+assert.throws(RangeError, () => cal.dateFromFields(
+ {year: 2021, monthCode: "M00", day: 5}, {overflow: "reject"}),
+ 'cal.dateFromFields( {year: 2021, monthCode: "M00", day: 5}, {overflow: "reject"}) throws a RangeError exception');
+assert.throws(RangeError, () => cal.dateFromFields(
+ {year: 2021, monthCode: "M13", day: 5}, {overflow: "reject"}),
+ 'cal.dateFromFields( {year: 2021, monthCode: "M13", day: 5}, {overflow: "reject"}) throws a RangeError exception');
+
+assert.throws(RangeError, () => cal.dateFromFields(
+ {year: 2021, month: 12, day: 0}), 'cal.dateFromFields( {year: 2021, month: 12, day: 0}) throws a RangeError exception');
+assert.throws(RangeError, () => cal.dateFromFields(
+ {year: 2021, month: 0, day: 3}), 'cal.dateFromFields( {year: 2021, month: 0, day: 3}) throws a RangeError exception');
+
+// Check throw for the second arg
+assert.throws(RangeError, () => cal.dateFromFields(
+ {year: 2021, month: 7, day: 13}, {overflow: "invalid"}), 'cal.dateFromFields( {year: 2021, month: 7, day: 13}, {overflow: "invalid"}) throws a RangeError exception');
+
+assert.throws(RangeError, () => cal.dateFromFields(
+ {year: 2021, month: 1, day: 32}, {overflow: "reject"}), 'cal.dateFromFields( {year: 2021, month: 1, day: 32}, {overflow: "reject"}) throws a RangeError exception');
+assert.throws(RangeError, () => cal.dateFromFields(
+ {year: 2021, month: 2, day: 29}, {overflow: "reject"}), 'cal.dateFromFields( {year: 2021, month: 2, day: 29}, {overflow: "reject"}) throws a RangeError exception');
+assert.throws(RangeError, () => cal.dateFromFields(
+ {year: 2021, month: 3, day: 32}, {overflow: "reject"}), 'cal.dateFromFields( {year: 2021, month: 3, day: 32}, {overflow: "reject"}) throws a RangeError exception');
+assert.throws(RangeError, () => cal.dateFromFields(
+ {year: 2021, month: 4, day: 31}, {overflow: "reject"}), 'cal.dateFromFields( {year: 2021, month: 4, day: 31}, {overflow: "reject"}) throws a RangeError exception');
+assert.throws(RangeError, () => cal.dateFromFields(
+ {year: 2021, month: 5, day: 32}, {overflow: "reject"}), 'cal.dateFromFields( {year: 2021, month: 5, day: 32}, {overflow: "reject"}) throws a RangeError exception');
+assert.throws(RangeError, () => cal.dateFromFields(
+ {year: 2021, month: 6, day: 31}, {overflow: "reject"}), 'cal.dateFromFields( {year: 2021, month: 6, day: 31}, {overflow: "reject"}) throws a RangeError exception');
+assert.throws(RangeError, () => cal.dateFromFields(
+ {year: 2021, month: 7, day: 32}, {overflow: "reject"}), 'cal.dateFromFields( {year: 2021, month: 7, day: 32}, {overflow: "reject"}) throws a RangeError exception');
+assert.throws(RangeError, () => cal.dateFromFields(
+ {year: 2021, month: 8, day: 32}, {overflow: "reject"}), 'cal.dateFromFields( {year: 2021, month: 8, day: 32}, {overflow: "reject"}) throws a RangeError exception');
+assert.throws(RangeError, () => cal.dateFromFields(
+ {year: 2021, month: 9, day: 31}, {overflow: "reject"}), 'cal.dateFromFields( {year: 2021, month: 9, day: 31}, {overflow: "reject"}) throws a RangeError exception');
+assert.throws(RangeError, () => cal.dateFromFields(
+ {year: 2021, month: 10, day: 32}, {overflow: "reject"}), 'cal.dateFromFields( {year: 2021, month: 10, day: 32}, {overflow: "reject"}) throws a RangeError exception');
+assert.throws(RangeError, () => cal.dateFromFields(
+ {year: 2021, month: 11, day: 31}, {overflow: "reject"}), 'cal.dateFromFields( {year: 2021, month: 11, day: 31}, {overflow: "reject"}) throws a RangeError exception');
+assert.throws(RangeError, () => cal.dateFromFields(
+ {year: 2021, month: 12, day: 32}, {overflow: "reject"}), 'cal.dateFromFields( {year: 2021, month: 12, day: 32}, {overflow: "reject"}) throws a RangeError exception');
+assert.throws(RangeError, () => cal.dateFromFields(
+ {year: 2021, month: 13, day: 5}, {overflow: "reject"}), 'cal.dateFromFields( {year: 2021, month: 13, day: 5}, {overflow: "reject"}) throws a RangeError exception');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/throws-type-error.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/throws-type-error.js
new file mode 100644
index 0000000000..83b69f4d9f
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/throws-type-error.js
@@ -0,0 +1,58 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.datefromfields
+description: Temporal.Calendar.prototype.dateFromFields should throw TypeError with wrong type.
+info: |
+ 1. Let calendar be the this value.
+ 2. Perform ? RequireInternalSlot(calendar, [[InitializedTemporalCalendar]]).
+ 3. Assert: calendar.[[Identifier]] is "iso8601".
+ 4. If Type(fields) is not Object, throw a TypeError exception.
+ 5. Set options to ? GetOptionsObject(options).
+ 6. Let result be ? ISODateFromFields(fields, options).
+ 7. Return ? CreateTemporalDate(result.[[Year]], result.[[Month]], result.[[Day]], calendar).
+features: [BigInt, Symbol, Temporal, arrow-function]
+---*/
+// Check throw for first arg
+let cal = new Temporal.Calendar('iso8601');
+assert.throws(TypeError, () => cal.dateFromFields(), 'cal.dateFromFields() throws a TypeError exception');
+
+[undefined, true, false, 123, 456n, Symbol(), 'string'].forEach(function(fields) {
+ assert.throws(
+ TypeError,
+ () => cal.dateFromFields(fields),
+ 'cal.dateFromFields(fields) throws a TypeError exception'
+ );
+
+ assert.throws(
+ TypeError,
+ () => cal.dateFromFields(fields, undefined),
+ 'cal.dateFromFields(fields, undefined) throws a TypeError exception'
+ );
+
+ assert.throws(TypeError, () => cal.dateFromFields(fields, {
+ overflow: 'constrain'
+ }), 'cal.dateFromFields(fields, {overflow: "constrain"}) throws a TypeError exception');
+
+ assert.throws(TypeError, () => cal.dateFromFields(fields, {
+ overflow: 'reject'
+ }), 'cal.dateFromFields(fields, {overflow: "reject"}) throws a TypeError exception');
+});
+
+assert.throws(TypeError, () => cal.dateFromFields({
+ month: 1,
+ day: 17
+}), 'cal.dateFromFields({month: 1, day: 17}) throws a TypeError exception');
+
+assert.throws(TypeError, () => cal.dateFromFields({
+ year: 2021,
+ day: 17
+}), 'cal.dateFromFields({year: 2021, day: 17}) throws a TypeError exception');
+
+assert.throws(TypeError, () => cal.dateFromFields({
+ year: 2021,
+ month: 12
+}), 'cal.dateFromFields({year: 2021, month: 12}) throws a TypeError exception');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/with-year-month-day-need-constrain.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/with-year-month-day-need-constrain.js
new file mode 100644
index 0000000000..d2e766146e
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/with-year-month-day-need-constrain.js
@@ -0,0 +1,90 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.datefromfields
+description: Temporal.Calendar.prototype.dateFromFields with year/month/day and need constrain
+info: |
+ 1. Let calendar be the this value.
+ 2. Perform ? RequireInternalSlot(calendar, [[InitializedTemporalCalendar]]).
+ 3. Assert: calendar.[[Identifier]] is "iso8601".
+ 4. If Type(fields) is not Object, throw a TypeError exception.
+ 5. Set options to ? GetOptionsObject(options).
+ 6. Let result be ? ISODateFromFields(fields, options).
+ 7. Return ? CreateTemporalDate(result.[[Year]], result.[[Month]], result.[[Day]], calendar).
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+let cal = new Temporal.Calendar("iso8601")
+
+TemporalHelpers.assertPlainDate(
+ cal.dateFromFields({year: 2021, month: 1, day: 133}),
+ 2021, 1, "M01", 31,
+ "year/month/day with day need to be constrained in Jan");
+
+TemporalHelpers.assertPlainDate(
+ cal.dateFromFields({year: 2021, month: 2, day: 133}),
+ 2021, 2, "M02", 28,
+ "year/month/day with day need to be constrained in Feb");
+
+TemporalHelpers.assertPlainDate(
+ cal.dateFromFields({year: 2021, month: 3, day: 133}),
+ 2021, 3, "M03", 31,
+ "year/month/day with day need to be constrained in March");
+
+TemporalHelpers.assertPlainDate(
+ cal.dateFromFields({year: 2021, month: 4, day: 133}),
+ 2021, 4, "M04", 30,
+ "year/month/day with day need to be constrained in April");
+
+TemporalHelpers.assertPlainDate(
+ cal.dateFromFields({year: 2021, month: 5, day: 133}),
+ 2021, 5, "M05", 31,
+ "year/month/day with day need to be constrained in May");
+
+TemporalHelpers.assertPlainDate(
+ cal.dateFromFields({year: 2021, month: 6, day: 133}),
+ 2021, 6, "M06", 30,
+ "year/month/day with day need to be constrained in Jun");
+
+TemporalHelpers.assertPlainDate(
+ cal.dateFromFields({year: 2021, month: 7, day: 133}),
+ 2021, 7, "M07", 31,
+ "year/month/day with day need to be constrained in July");
+
+TemporalHelpers.assertPlainDate(
+ cal.dateFromFields({year: 2021, month: 8, day: 133}),
+ 2021, 8, "M08", 31,
+ "year/month/day with day need to be constrained in Aug");
+
+TemporalHelpers.assertPlainDate(
+ cal.dateFromFields({year: 2021, month: 9, day: 133}),
+ 2021, 9, "M09", 30,
+ "year/month/day with day need to be constrained in Sept.");
+
+TemporalHelpers.assertPlainDate(
+ cal.dateFromFields({year: 2021, month: 10, day: 133}),
+ 2021, 10, "M10", 31,
+ "year/month/day with day need to be constrained in Oct.");
+
+TemporalHelpers.assertPlainDate(
+ cal.dateFromFields({year: 2021, month: 11, day: 133}),
+ 2021, 11, "M11", 30,
+ "year/month/day with day need to be constrained in Nov.");
+
+TemporalHelpers.assertPlainDate(
+ cal.dateFromFields({year: 2021, month: 12, day: 133}),
+ 2021, 12, "M12", 31,
+ "year/month/day with day need to be constrained in Dec.");
+
+TemporalHelpers.assertPlainDate(
+ cal.dateFromFields({year: 2021, month: 13, day: 500}),
+ 2021, 12, "M12", 31,
+ "year/month/day with month and day need to be constrained");
+
+TemporalHelpers.assertPlainDate(
+ cal.dateFromFields({year: 2021, month: 999999, day: 500}),
+ 2021, 12, "M12", 31,
+ "year/month/day with month and day need to be constrained");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/with-year-month-day.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/with-year-month-day.js
new file mode 100644
index 0000000000..e24b574004
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/with-year-month-day.js
@@ -0,0 +1,25 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.datefromfields
+description: Temporal.Calendar.prototype.dateFromFields with year/month/day
+info: |
+ 1. Let calendar be the this value.
+ 2. Perform ? RequireInternalSlot(calendar, [[InitializedTemporalCalendar]]).
+ 3. Assert: calendar.[[Identifier]] is "iso8601".
+ 4. If Type(fields) is not Object, throw a TypeError exception.
+ 5. Set options to ? GetOptionsObject(options).
+ 6. Let result be ? ISODateFromFields(fields, options).
+ 7. Return ? CreateTemporalDate(result.[[Year]], result.[[Month]], result.[[Day]], calendar).
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+let cal = new Temporal.Calendar("iso8601")
+
+TemporalHelpers.assertPlainDate(
+ cal.dateFromFields({year: 2021, month: 7, day: 15}),
+ 2021, 7, "M07", 15,
+ "year/month/day");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/with-year-monthCode-day-need-constrain.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/with-year-monthCode-day-need-constrain.js
new file mode 100644
index 0000000000..175c34a601
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/with-year-monthCode-day-need-constrain.js
@@ -0,0 +1,80 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.datefromfields
+description: Temporal.Calendar.prototype.dateFromFields with year, monthCode and day and need constrain
+info: |
+ 1. Let calendar be the this value.
+ 2. Perform ? RequireInternalSlot(calendar, [[InitializedTemporalCalendar]]).
+ 3. Assert: calendar.[[Identifier]] is "iso8601".
+ 4. If Type(fields) is not Object, throw a TypeError exception.
+ 5. Set options to ? GetOptionsObject(options).
+ 6. Let result be ? ISODateFromFields(fields, options).
+ 7. Return ? CreateTemporalDate(result.[[Year]], result.[[Month]], result.[[Day]], calendar).
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+let cal = new Temporal.Calendar("iso8601")
+
+TemporalHelpers.assertPlainDate(
+ cal.dateFromFields({year: 2021, monthCode: "M01", day: 133}),
+ 2021, 1, "M01", 31,
+ "year/monthCode/day with day need to be constrained in Jan");
+
+TemporalHelpers.assertPlainDate(
+ cal.dateFromFields({year: 2021, monthCode: "M02", day: 133}),
+ 2021, 2, "M02", 28,
+ "year/monthCode/day with day need to be constrained in Feb");
+
+TemporalHelpers.assertPlainDate(
+ cal.dateFromFields({year: 2021, monthCode: "M03", day: 133}),
+ 2021, 3, "M03", 31,
+ "year/monthCode/day with day need to be constrained in March");
+
+TemporalHelpers.assertPlainDate(
+ cal.dateFromFields({year: 2021, monthCode: "M04", day: 133}),
+ 2021, 4, "M04", 30,
+ "year/monthCode/day with day need to be constrained in April");
+
+TemporalHelpers.assertPlainDate(
+ cal.dateFromFields({year: 2021, monthCode: "M05", day: 133}),
+ 2021, 5, "M05", 31,
+ "year/monthCode/day with day need to be constrained in May");
+
+TemporalHelpers.assertPlainDate(
+ cal.dateFromFields({year: 2021, monthCode: "M06", day: 133}),
+ 2021, 6, "M06", 30,
+ "year/monthCode/day with day need to be constrained in Jun");
+
+TemporalHelpers.assertPlainDate(
+ cal.dateFromFields({year: 2021, monthCode: "M07", day: 133}),
+ 2021, 7, "M07", 31,
+ "year/monthCode/day with day need to be constrained in July");
+
+TemporalHelpers.assertPlainDate(
+ cal.dateFromFields({year: 2021, monthCode: "M08", day: 133}),
+ 2021, 8, "M08", 31,
+ "year/monthCode/day with day need to be constrained in Aug");
+
+TemporalHelpers.assertPlainDate(
+ cal.dateFromFields({year: 2021, monthCode: "M09", day: 133}),
+ 2021, 9, "M09", 30,
+ "year/monthCode/day with day need to be constrained in Sept.");
+
+TemporalHelpers.assertPlainDate(
+ cal.dateFromFields({year: 2021, monthCode: "M10", day: 133}),
+ 2021, 10, "M10", 31,
+ "year/monthCode/day with day need to be constrained in Oct.");
+
+TemporalHelpers.assertPlainDate(
+ cal.dateFromFields({year: 2021, monthCode: "M11", day: 133}),
+ 2021, 11, "M11", 30,
+ "year/monthCode/day with day need to be constrained in Nov.");
+
+TemporalHelpers.assertPlainDate(
+ cal.dateFromFields({year: 2021, monthCode: "M12", day: 133}),
+ 2021, 12, "M12", 31,
+ "year/monthCode/day with day need to be constrained in Dec.");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/with-year-monthCode-day.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/with-year-monthCode-day.js
new file mode 100644
index 0000000000..ff07ed1935
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateFromFields/with-year-monthCode-day.js
@@ -0,0 +1,25 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.datefromfields
+description: Temporal.Calendar.prototype.dateFromFields with year, monthCode and day.
+info: |
+ 1. Let calendar be the this value.
+ 2. Perform ? RequireInternalSlot(calendar, [[InitializedTemporalCalendar]]).
+ 3. Assert: calendar.[[Identifier]] is "iso8601".
+ 4. If Type(fields) is not Object, throw a TypeError exception.
+ 5. Set options to ? GetOptionsObject(options).
+ 6. Let result be ? ISODateFromFields(fields, options).
+ 7. Return ? CreateTemporalDate(result.[[Year]], result.[[Month]], result.[[Day]], calendar).
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+let cal = new Temporal.Calendar("iso8601")
+
+TemporalHelpers.assertPlainDate(
+ cal.dateFromFields({year: 2021, monthCode: "M07", day: 15}),
+ 2021, 7, "M07", 15,
+ "year/monthCode/day");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-builtin-calendar-no-array-iteration.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-builtin-calendar-no-array-iteration.js
new file mode 100644
index 0000000000..ef09180179
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-builtin-calendar-no-array-iteration.js
@@ -0,0 +1,25 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateuntil
+description: >
+ Calling the method with a property bag argument with a builtin calendar causes
+ no observable array iteration when getting the calendar fields.
+features: [Temporal]
+---*/
+
+const arrayPrototypeSymbolIteratorOriginal = Array.prototype[Symbol.iterator];
+Array.prototype[Symbol.iterator] = function arrayIterator() {
+ throw new Test262Error("Array should not be iterated");
+}
+
+const instance = new Temporal.Calendar("iso8601");
+const arg = { year: 2000, month: 5, day: 2, calendar: "iso8601" };
+instance.dateUntil(arg, new Temporal.PlainDate(1977, 11, 19));
+instance.dateUntil(new Temporal.PlainDate(1977, 11, 19), arg);
+
+Array.prototype[Symbol.iterator] = arrayPrototypeSymbolIteratorOriginal;
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-calendar-datefromfields-called-with-null-prototype-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-calendar-datefromfields-called-with-null-prototype-fields.js
new file mode 100644
index 0000000000..0385c15b1e
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-calendar-datefromfields-called-with-null-prototype-fields.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateuntil
+description: >
+ Calendar.dateFromFields method is called with a null-prototype fields object
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarCheckFieldsPrototypePollution();
+const instance = new Temporal.Calendar("iso8601");
+const arg1 = { year: 2000, month: 5, day: 2, calendar };
+const arg2 = new Temporal.PlainDate(1977, 11, 19);
+
+instance.dateUntil(arg1, arg2);
+assert.sameValue(calendar.dateFromFieldsCallCount, 1, "dateFromFields should be called on the property bag's calendar (first argument)");
+
+calendar.dateFromFieldsCallCount = 0;
+
+instance.dateUntil(arg2, arg1);
+assert.sameValue(calendar.dateFromFieldsCallCount, 1, "dateFromFields should be called on the property bag's calendar (second argument)");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-constructor-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-constructor-in-calendar-fields.js
new file mode 100644
index 0000000000..1f24241be6
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-constructor-in-calendar-fields.js
@@ -0,0 +1,17 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.dateuntil
+description: If a calendar's fields() method returns a field named 'constructor', PrepareTemporalFields should throw a RangeError.
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarWithExtraFields(['constructor']);
+const arg = {year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar};
+const instance = new Temporal.Calendar("iso8601");
+
+assert.throws(RangeError, () => instance.dateUntil(arg, new Temporal.PlainDate(1977, 11, 19)));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-duplicate-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-duplicate-calendar-fields.js
new file mode 100644
index 0000000000..5becde2c5a
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-duplicate-calendar-fields.js
@@ -0,0 +1,20 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.dateuntil
+description: If a calendar's fields() method returns duplicate field names, PrepareTemporalFields should throw a RangeError.
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+for (const extra_fields of [['foo', 'foo'], ['day'], ['month'], ['monthCode'], ['year']]) {
+ const calendar = TemporalHelpers.calendarWithExtraFields(extra_fields);
+ const arg = { year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar };
+ const instance = new Temporal.Calendar("iso8601");
+
+ assert.throws(RangeError, () => instance.dateUntil(arg, new Temporal.PlainDate(1977, 11, 19)));
+ assert.throws(RangeError, () => instance.dateUntil(new Temporal.PlainDate(1977, 11, 19), arg));
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-infinity-throws-rangeerror.js
new file mode 100644
index 0000000000..5123301475
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-infinity-throws-rangeerror.js
@@ -0,0 +1,34 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: Throws if any value in a property bag for either argument is Infinity or -Infinity
+esid: sec-temporal.calendar.prototype.dateuntil
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+const other = new Temporal.PlainDate(2001, 6, 3);
+const base = { year: 2000, month: 5, day: 2 };
+
+[Infinity, -Infinity].forEach((inf) => {
+ ["year", "month", "day"].forEach((prop) => {
+ assert.throws(RangeError, () => instance.dateUntil({ ...base, [prop]: inf }, other), `${prop} property cannot be ${inf}`);
+
+ assert.throws(RangeError, () => instance.dateUntil(other, { ...base, [prop]: inf }), `${prop} property cannot be ${inf}`);
+
+ const calls1 = [];
+ const obj1 = TemporalHelpers.toPrimitiveObserver(calls1, inf, prop);
+ assert.throws(RangeError, () => instance.dateUntil({ ...base, [prop]: obj1 }, other));
+ assert.compareArray(calls1, [`get ${prop}.valueOf`, `call ${prop}.valueOf`], "it fails after fetching the primitive value");
+
+ const calls2 = [];
+ const obj2 = TemporalHelpers.toPrimitiveObserver(calls2, inf, prop);
+ assert.throws(RangeError, () => instance.dateUntil(other, { ...base, [prop]: obj2 }));
+ assert.compareArray(calls2, [`get ${prop}.valueOf`, `call ${prop}.valueOf`], "it fails after fetching the primitive value");
+ });
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-number.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-number.js
new file mode 100644
index 0000000000..4a8ba0f55d
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-number.js
@@ -0,0 +1,33 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateuntil
+description: A number cannot be used in place of a Temporal.PlainDate
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const numbers = [
+ 1,
+ 19761118,
+ -19761118,
+ 1234567890,
+];
+
+for (const arg of numbers) {
+ assert.throws(
+ TypeError,
+ () => instance.dateUntil(arg, new Temporal.PlainDate(1977, 11, 18)),
+ "A number is not a valid ISO string for PlainDate (first argument)"
+ );
+ assert.throws(
+ TypeError,
+ () => instance.dateUntil(new Temporal.PlainDate(1977, 11, 18), arg),
+ "A number is not a valid ISO string for PlainDate (second argument)"
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-plaindatetime.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-plaindatetime.js
new file mode 100644
index 0000000000..526b151206
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-plaindatetime.js
@@ -0,0 +1,33 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateuntil
+description: Fast path for converting Temporal.PlainDateTime to Temporal.PlainDate by reading internal slots
+info: |
+ sec-temporal.calendar.prototype.dateuntil steps 4–5:
+ 4. Set _one_ to ? ToTemporalDate(_one_).
+ 5. Set _two_ to ? ToTemporalDate(_two_).
+ sec-temporal-totemporaldate step 2.b:
+ b. If _item_ has an [[InitializedTemporalDateTime]] internal slot, then
+ i. Return ! CreateTemporalDate(_item_.[[ISOYear]], _item_.[[ISOMonth]], _item_.[[ISODay]], _item_.[[Calendar]]).
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const date = new Temporal.PlainDate(2000, 5, 2);
+
+TemporalHelpers.checkPlainDateTimeConversionFastPath((datetime) => {
+ const calendar = new Temporal.Calendar("iso8601");
+ const result = calendar.dateUntil(datetime, date);
+ assert.sameValue(result.total({ unit: "nanoseconds" }), 0, "time part dropped");
+});
+
+TemporalHelpers.checkPlainDateTimeConversionFastPath((datetime) => {
+ const calendar = new Temporal.Calendar("iso8601");
+ const result = calendar.dateUntil(date, datetime);
+ assert.sameValue(result.total({ unit: "nanoseconds" }), 0, "time part dropped");
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-propertybag-calendar-case-insensitive.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-propertybag-calendar-case-insensitive.js
new file mode 100644
index 0000000000..89b104bb17
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-propertybag-calendar-case-insensitive.js
@@ -0,0 +1,22 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateuntil
+description: The calendar name is case-insensitive
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const calendar = "IsO8601";
+
+const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+const result1 = instance.dateUntil(arg, new Temporal.PlainDate(1976, 11, 19));
+TemporalHelpers.assertDuration(result1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, "Calendar is case-insensitive (first argument)");
+const result2 = instance.dateUntil(new Temporal.PlainDate(1976, 11, 19), arg);
+TemporalHelpers.assertDuration(result2, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, "Calendar is case-insensitive (second argument)");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-propertybag-calendar-leap-second.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-propertybag-calendar-leap-second.js
new file mode 100644
index 0000000000..712bf74a46
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-propertybag-calendar-leap-second.js
@@ -0,0 +1,22 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateuntil
+description: Leap second is a valid ISO string for a calendar in a property bag
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const calendar = "2016-12-31T23:59:60";
+
+const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+const result1 = instance.dateUntil(arg, new Temporal.PlainDate(1976, 11, 19));
+TemporalHelpers.assertDuration(result1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, "leap second is a valid ISO string for calendar (first argument)");
+const result2 = instance.dateUntil(new Temporal.PlainDate(1976, 11, 19), arg);
+TemporalHelpers.assertDuration(result2, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, "leap second is a valid ISO string for calendar (second argument)");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-propertybag-calendar-number.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-propertybag-calendar-number.js
new file mode 100644
index 0000000000..9d2fd6a583
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-propertybag-calendar-number.js
@@ -0,0 +1,34 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateuntil
+description: A number as calendar in a property bag is not accepted
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const numbers = [
+ 1,
+ 19970327,
+ -19970327,
+ 1234567890,
+];
+
+for (const calendar of numbers) {
+ const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+ assert.throws(
+ TypeError,
+ () => instance.dateUntil(arg, new Temporal.PlainDate(1977, 11, 19)),
+ "A number is not a valid ISO string for calendar (first argument)"
+ );
+ assert.throws(
+ TypeError,
+ () => instance.dateUntil(new Temporal.PlainDate(1977, 11, 19), arg),
+ "A number is not a valid ISO string for calendar (second argument)"
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-propertybag-calendar-string.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-propertybag-calendar-string.js
new file mode 100644
index 0000000000..037111eaa5
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-propertybag-calendar-string.js
@@ -0,0 +1,31 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateuntil
+description: A calendar ID is valid input for Calendar
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+Object.defineProperty(instance, "dateFromFields", {
+ configurable: true,
+ enumerable: false,
+ get() {
+ TemporalHelpers.assertUnreachable("dateFromFields should not be looked up on receiver");
+ },
+});
+
+const calendar = "iso8601";
+
+const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+
+const result1 = instance.dateUntil(arg, new Temporal.PlainDate(1976, 11, 18));
+TemporalHelpers.assertDuration(result1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, `Calendar created from string "${arg} (first argument)"`);
+
+const result2 = instance.dateUntil(new Temporal.PlainDate(1976, 11, 18), arg);
+TemporalHelpers.assertDuration(result2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, `Calendar created from string "${arg} (second argument)"`);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-propertybag-calendar-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-propertybag-calendar-wrong-type.js
new file mode 100644
index 0000000000..245fbf46da
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-propertybag-calendar-wrong-type.js
@@ -0,0 +1,52 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateuntil
+description: >
+ Appropriate error thrown when a calendar property from a property bag cannot
+ be converted to a calendar object or string
+features: [BigInt, Symbol, Temporal]
+---*/
+
+const timeZone = new Temporal.TimeZone("UTC");
+const instance = new Temporal.Calendar("iso8601");
+
+const primitiveTests = [
+ [null, "null"],
+ [true, "boolean"],
+ ["", "empty string"],
+ [1, "number that doesn't convert to a valid ISO string"],
+ [1n, "bigint"],
+];
+
+for (const [calendar, description] of primitiveTests) {
+ const arg = { year: 2019, monthCode: "M11", day: 1, calendar };
+ assert.throws(
+ typeof calendar === "string" ? RangeError : TypeError,
+ () => instance.dateUntil(arg, new Temporal.PlainDate(1977, 11, 19)),
+ `${description} does not convert to a valid ISO string (first argument)`
+ );
+ assert.throws(
+ typeof calendar === "string" ? RangeError : TypeError,
+ () => instance.dateUntil(new Temporal.PlainDate(1977, 11, 19), arg),
+ `${description} does not convert to a valid ISO string (second argument)`
+ );
+}
+
+const typeErrorTests = [
+ [Symbol(), "symbol"],
+ [{}, "plain object that doesn't implement the protocol"],
+ [new Temporal.TimeZone("UTC"), "time zone instance"],
+ [Temporal.Calendar, "Temporal.Calendar, object"],
+ [Temporal.Calendar.prototype, "Temporal.Calendar.prototype, object"], // fails brand check in dateFromFields()
+];
+
+for (const [calendar, description] of typeErrorTests) {
+ const arg = { year: 2019, monthCode: "M11", day: 1, calendar };
+ assert.throws(TypeError, () => instance.dateUntil(arg, new Temporal.PlainDate(1977, 11, 19)), `${description} is not a valid property bag and does not convert to a string (first argument)`);
+ assert.throws(TypeError, () => instance.dateUntil(new Temporal.PlainDate(1977, 11, 19), arg), `${description} is not a valid property bag and does not convert to a string (second argument)`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-propertybag-calendar-year-zero.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-propertybag-calendar-year-zero.js
new file mode 100644
index 0000000000..117c3e627f
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-propertybag-calendar-year-zero.js
@@ -0,0 +1,32 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateuntil
+description: Negative zero, as an extended year, is rejected
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ "-000000-10-31",
+ "-000000-10-31T17:45",
+ "-000000-10-31T17:45Z",
+ "-000000-10-31T17:45+01:00",
+ "-000000-10-31T17:45+00:00[UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.dateUntil(arg, new Temporal.PlainDate(1977, 11, 19)),
+ "reject minus zero as extended year (first argument)"
+ );
+ assert.throws(
+ RangeError,
+ () => instance.dateUntil(new Temporal.PlainDate(1977, 11, 19), arg),
+ "reject minus zero as extended year (second argument)"
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-proto-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-proto-in-calendar-fields.js
new file mode 100644
index 0000000000..34e8f2c28c
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-proto-in-calendar-fields.js
@@ -0,0 +1,17 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.dateuntil
+description: If a calendar's fields() method returns a field named '__proto__', PrepareTemporalFields should throw a RangeError.
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarWithExtraFields(['__proto__']);
+const arg = {year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar};
+const instance = new Temporal.Calendar("iso8601");
+
+assert.throws(RangeError, () => instance.dateUntil(arg, new Temporal.PlainDate(1977, 11, 19)));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-string-calendar-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-string-calendar-annotation.js
new file mode 100644
index 0000000000..069f193cc9
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-string-calendar-annotation.js
@@ -0,0 +1,34 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateuntil
+description: Various forms of calendar annotation; critical flag has no effect
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+const tests = [
+ ["2000-05-02[u-ca=iso8601]", "without time or time zone"],
+ ["2000-05-02[UTC][u-ca=iso8601]", "with time zone and no time"],
+ ["2000-05-02T15:23[u-ca=iso8601]", "without time zone"],
+ ["2000-05-02T15:23[UTC][u-ca=iso8601]", "with time zone"],
+ ["2000-05-02T15:23[!u-ca=iso8601]", "with ! and no time zone"],
+ ["2000-05-02T15:23[UTC][!u-ca=iso8601]", "with ! and time zone"],
+ ["2000-05-02T15:23[u-ca=iso8601][u-ca=discord]", "second annotation ignored"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.dateUntil(arg, arg);
+
+ TemporalHelpers.assertDuration(
+ result,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ `calendar annotation (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-string-critical-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-string-critical-unknown-annotation.js
new file mode 100644
index 0000000000..97efa5c7e6
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-string-critical-unknown-annotation.js
@@ -0,0 +1,33 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateuntil
+description: Unknown annotations with critical flag are rejected
+features: [Temporal]
+---*/
+
+const invalidStrings = [
+ "1970-01-01[!foo=bar]",
+ "1970-01-01T00:00[!foo=bar]",
+ "1970-01-01T00:00[UTC][!foo=bar]",
+ "1970-01-01T00:00[u-ca=iso8601][!foo=bar]",
+ "1970-01-01T00:00[UTC][!foo=bar][u-ca=iso8601]",
+ "1970-01-01T00:00[foo=bar][!_foo-bar0=Dont-Ignore-This-99999999999]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.dateUntil(arg, new Temporal.PlainDate(1977, 11, 19)),
+ `reject unknown annotation with critical flag: ${arg} (first argument)`
+ );
+ assert.throws(
+ RangeError,
+ () => instance.dateUntil(new Temporal.PlainDate(1977, 11, 19), arg),
+ `reject unknown annotation with critical flag: ${arg} (second argument)`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-string-date-with-utc-offset.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-string-date-with-utc-offset.js
new file mode 100644
index 0000000000..47db3e2de7
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-string-date-with-utc-offset.js
@@ -0,0 +1,52 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateuntil
+description: UTC offset not valid with format that does not include a time
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const validStrings = [
+ "2000-05-02T00+00:00",
+ "2000-05-02T00+00:00[UTC]",
+ "2000-05-02T00+00:00[!UTC]",
+ "2000-05-02T00-02:30[America/St_Johns]",
+];
+
+for (const arg of validStrings) {
+ TemporalHelpers.assertDuration(
+ instance.dateUntil(arg, arg),
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ `"${arg}" is a valid UTC offset with time for PlainDate`
+ );
+}
+
+const invalidStrings = [
+ "2022-09-15Z",
+ "2022-09-15Z[UTC]",
+ "2022-09-15Z[Europe/Vienna]",
+ "2022-09-15+00:00",
+ "2022-09-15+00:00[UTC]",
+ "2022-09-15-02:30",
+ "2022-09-15-02:30[America/St_Johns]",
+];
+
+for (const arg of invalidStrings) {
+ assert.throws(
+ RangeError,
+ () => instance.dateUntil(arg, new Temporal.PlainDate(1977, 11, 19)),
+ `"${arg}" UTC offset without time is not valid for PlainDate (first argument)`
+ );
+ assert.throws(
+ RangeError,
+ () => instance.dateUntil(new Temporal.PlainDate(1977, 11, 19), arg),
+ `"${arg}" UTC offset without time is not valid for PlainDate (second argument)`
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-string-invalid.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-string-invalid.js
new file mode 100644
index 0000000000..31c39e90a0
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-string-invalid.js
@@ -0,0 +1,70 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateuntil
+description: >
+ RangeError thrown if an invalid ISO string (or syntactically valid ISO string
+ that is not supported) is used as a PlainDate
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ // invalid ISO strings:
+ "",
+ "invalid iso8601",
+ "2020-01-00",
+ "2020-01-32",
+ "2020-02-30",
+ "2021-02-29",
+ "2020-00-01",
+ "2020-13-01",
+ "2020-01-01T",
+ "2020-01-01T25:00:00",
+ "2020-01-01T01:60:00",
+ "2020-01-01T01:60:61",
+ "2020-01-01junk",
+ "2020-01-01T00:00:00junk",
+ "2020-01-01T00:00:00+00:00junk",
+ "2020-01-01T00:00:00+00:00[UTC]junk",
+ "2020-01-01T00:00:00+00:00[UTC][u-ca=iso8601]junk",
+ "02020-01-01",
+ "2020-001-01",
+ "2020-01-001",
+ "2020-01-01T001",
+ "2020-01-01T01:001",
+ "2020-01-01T01:01:001",
+ // valid, but forms not supported in Temporal:
+ "2020-W01-1",
+ "2020-001",
+ "+0002020-01-01",
+ // valid, but this calendar must not exist:
+ "2020-01-01[u-ca=notexist]",
+ // may be valid in other contexts, but insufficient information for PlainDate:
+ "2020-01",
+ "+002020-01",
+ "01-01",
+ "2020-W01",
+ "P1Y",
+ "-P12Y",
+ // valid, but outside the supported range:
+ "-999999-01-01",
+ "+999999-01-01",
+];
+const instance = new Temporal.Calendar("iso8601");
+const other = new Temporal.PlainDate(2020, 1, 1, instance);
+for (const arg of invalidStrings) {
+ assert.throws(
+ RangeError,
+ () => instance.dateUntil(arg, other),
+ `"${arg}" should not be a valid ISO string for a PlainDate (first argument)`
+ );
+ assert.throws(
+ RangeError,
+ () => instance.dateUntil(other, arg),
+ `"${arg}" should not be a valid ISO string for a PlainDate (second argument)`
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-string-multiple-calendar.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-string-multiple-calendar.js
new file mode 100644
index 0000000000..e8ba951085
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-string-multiple-calendar.js
@@ -0,0 +1,37 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateuntil
+description: >
+ More than one calendar annotation is not syntactical if any have the criical
+ flag
+features: [Temporal]
+---*/
+
+const invalidStrings = [
+ "1970-01-01[u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01[!u-ca=iso8601][u-ca=iso8601]",
+ "1970-01-01[UTC][u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01[u-ca=iso8601][foo=bar][!u-ca=iso8601]",
+ "1970-01-01T00:00[u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01T00:00[!u-ca=iso8601][u-ca=iso8601]",
+ "1970-01-01T00:00[UTC][u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01T00:00[u-ca=iso8601][foo=bar][!u-ca=iso8601]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.dateUntil(arg, new Temporal.PlainDate(1977, 11, 19)),
+ `reject more than one calendar annotation if any critical: ${arg} (first argument)`
+ );
+ assert.throws(
+ RangeError,
+ () => instance.dateUntil(new Temporal.PlainDate(1977, 11, 19), arg),
+ `reject more than one calendar annotation if any critical: ${arg} (second argument)`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-string-multiple-time-zone.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-string-multiple-time-zone.js
new file mode 100644
index 0000000000..db2cbbf925
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-string-multiple-time-zone.js
@@ -0,0 +1,33 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateuntil
+description: More than one time zone annotation is not syntactical
+features: [Temporal]
+---*/
+
+const invalidStrings = [
+ "1970-01-01[UTC][UTC]",
+ "1970-01-01T00:00[UTC][UTC]",
+ "1970-01-01T00:00[!UTC][UTC]",
+ "1970-01-01T00:00[UTC][!UTC]",
+ "1970-01-01T00:00[UTC][u-ca=iso8601][UTC]",
+ "1970-01-01T00:00[UTC][foo=bar][UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.dateUntil(arg, new Temporal.PlainDate(1977, 11, 19)),
+ `reject more than one time zone annotation: ${arg} (first argument)`
+ );
+ assert.throws(
+ RangeError,
+ () => instance.dateUntil(new Temporal.PlainDate(1977, 11, 19), arg),
+ `reject more than one time zone annotation: ${arg} (second argument)`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-string-time-separators.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-string-time-separators.js
new file mode 100644
index 0000000000..06a8f07274
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-string-time-separators.js
@@ -0,0 +1,35 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateuntil
+description: Time separator in string argument can vary
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+const date = new Temporal.PlainDate(2000, 5, 3);
+const tests = [
+ ["2000-05-02T15:23", "uppercase T"],
+ ["2000-05-02t15:23", "lowercase T"],
+ ["2000-05-02 15:23", "space between date and time"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ TemporalHelpers.assertDuration(
+ instance.dateUntil(arg, date),
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
+ `variant time separators (${description}), first argument`
+ );
+
+ TemporalHelpers.assertDuration(
+ instance.dateUntil(date, arg),
+ 0, 0, 0, -1, 0, 0, 0, 0, 0, 0,
+ `variant time separators (${description}), second argument`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-string-time-zone-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-string-time-zone-annotation.js
new file mode 100644
index 0000000000..66159880e5
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-string-time-zone-annotation.js
@@ -0,0 +1,39 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateuntil
+description: Various forms of time zone annotation; critical flag has no effect
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+const tests = [
+ ['2000-05-02[Asia/Kolkata]', 'named, with no time'],
+ ['2000-05-02[!Europe/Vienna]', 'named, with ! and no time'],
+ ['2000-05-02[+00:00]', 'numeric, with no time'],
+ ['2000-05-02[!-02:30]', 'numeric, with ! and no time'],
+ ["2000-05-02T15:23[America/Sao_Paulo]", "named, with no offset"],
+ ["2000-05-02T15:23[!Asia/Tokyo]", "named, with ! and no offset"],
+ ["2000-05-02T15:23[-02:30]", "numeric, with no offset"],
+ ["2000-05-02T15:23[!+00:00]", "numeric, with ! and no offset"],
+ ["2000-05-02T15:23+00:00[America/New_York]", "named, with offset"],
+ ["2000-05-02T15:23+00:00[!UTC]", "named, with offset and !"],
+ ["2000-05-02T15:23+00:00[+01:00]", "numeric, with offset"],
+ ["2000-05-02T15:23+00:00[!-08:00]", "numeric, with offset and !"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.dateUntil(arg, arg);
+
+ TemporalHelpers.assertDuration(
+ result,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ `time zone annotation (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-string-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-string-unknown-annotation.js
new file mode 100644
index 0000000000..5f151e4bf8
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-string-unknown-annotation.js
@@ -0,0 +1,33 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateuntil
+description: Various forms of unknown annotation
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+const tests = [
+ ["2000-05-02[foo=bar]", "without time"],
+ ["2000-05-02T15:23[foo=bar]", "alone"],
+ ["2000-05-02T15:23[UTC][foo=bar]", "with time zone"],
+ ["2000-05-02T15:23[u-ca=iso8601][foo=bar]", "with calendar"],
+ ["2000-05-02T15:23[UTC][foo=bar][u-ca=iso8601]", "with time zone and calendar"],
+ ["2000-05-02T15:23[foo=bar][_foo-bar0=Ignore-This-999999999999]", "with another unknown annotation"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.dateUntil(arg, arg);
+
+ TemporalHelpers.assertDuration(
+ result,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ `unknown annotation (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-string-with-utc-designator.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-string-with-utc-designator.js
new file mode 100644
index 0000000000..2a7ae86b76
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-string-with-utc-designator.js
@@ -0,0 +1,30 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateuntil
+description: RangeError thrown if a string with UTC designator is used as a PlainDate
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ "2019-10-01T09:00:00Z",
+ "2019-10-01T09:00:00Z[UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+const plainDate = new Temporal.PlainDate(2000, 5, 2);
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.dateUntil(arg, plainDate),
+ "String with UTC designator should not be valid as a PlainDate (first argument)"
+ );
+ assert.throws(
+ RangeError,
+ () => instance.dateUntil(plainDate, arg),
+ "String with UTC designator should not be valid as a PlainDate (second argument)"
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-wrong-type.js
new file mode 100644
index 0000000000..da9c257fc0
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-wrong-type.js
@@ -0,0 +1,50 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateuntil
+description: >
+ Appropriate error thrown when argument cannot be converted to a valid string
+ or property bag for PlainDate
+features: [BigInt, Symbol, Temporal]
+---*/
+
+const timeZone = new Temporal.TimeZone("UTC");
+const instance = new Temporal.Calendar("iso8601");
+
+const primitiveTests = [
+ [undefined, "undefined"],
+ [null, "null"],
+ [true, "boolean"],
+ ["", "empty string"],
+ [1, "number that doesn't convert to a valid ISO string"],
+ [1n, "bigint"],
+];
+
+for (const [arg, description] of primitiveTests) {
+ assert.throws(
+ typeof arg === 'string' ? RangeError : TypeError,
+ () => instance.dateUntil(arg, new Temporal.PlainDate(1977, 11, 19)),
+ `${description} does not convert to a valid ISO string (first argument)`
+ );
+ assert.throws(
+ typeof arg === 'string' ? RangeError : TypeError,
+ () => instance.dateUntil(new Temporal.PlainDate(1977, 11, 19), arg),
+ `${description} does not convert to a valid ISO string (second argument)`
+ );
+}
+
+const typeErrorTests = [
+ [Symbol(), "symbol"],
+ [{}, "plain object"],
+ [Temporal.PlainDate, "Temporal.PlainDate, object"],
+ [Temporal.PlainDate.prototype, "Temporal.PlainDate.prototype, object"],
+];
+
+for (const [arg, description] of typeErrorTests) {
+ assert.throws(TypeError, () => instance.dateUntil(arg, new Temporal.PlainDate(1977, 11, 19)), `${description} is not a valid property bag and does not convert to a string (first argument)`);
+ assert.throws(TypeError, () => instance.dateUntil(new Temporal.PlainDate(1977, 11, 19), arg), `${description} is not a valid property bag and does not convert to a string (second argument)`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-zoneddatetime-slots.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-zoneddatetime-slots.js
new file mode 100644
index 0000000000..6a09cb6ed5
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-zoneddatetime-slots.js
@@ -0,0 +1,41 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateuntil
+description: Getters are not called when converting a ZonedDateTime to a PlainDate.
+includes: [compareArray.js]
+features: [Temporal]
+---*/
+
+const actual = [];
+const prototypeDescrs = Object.getOwnPropertyDescriptors(Temporal.ZonedDateTime.prototype);
+const getters = ["year", "month", "monthCode", "day", "hour", "minute", "second", "millisecond", "microsecond", "nanosecond", "calendar"];
+
+for (const property of getters) {
+ Object.defineProperty(Temporal.ZonedDateTime.prototype, property, {
+ get() {
+ actual.push(`get ${property}`);
+ const value = prototypeDescrs[property].get.call(this);
+ return {
+ toString() {
+ actual.push(`toString ${property}`);
+ return value.toString();
+ },
+ valueOf() {
+ actual.push(`valueOf ${property}`);
+ return value;
+ },
+ };
+ },
+ });
+}
+
+const arg = new Temporal.ZonedDateTime(0n, "UTC");
+const instance = new Temporal.Calendar("iso8601");
+instance.dateUntil(arg, new Temporal.PlainDate(1977, 11, 19));
+instance.dateUntil(new Temporal.PlainDate(1977, 11, 19), arg);
+assert.compareArray(actual, []);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js
new file mode 100644
index 0000000000..70c9fc1a12
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js
@@ -0,0 +1,22 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateuntil
+description: RangeError thrown if time zone reports an offset that is not an integer number of nanoseconds
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+[3600_000_000_000.5, NaN, Infinity, -Infinity].forEach((wrongOffset) => {
+ const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset);
+ const calendar = new Temporal.Calendar("iso8601");
+ const date = new Temporal.PlainDate(2000, 5, 2);
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+
+ assert.throws(RangeError, () => calendar.dateUntil(datetime, date));
+ assert.throws(RangeError, () => calendar.dateUntil(date, datetime));
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js
new file mode 100644
index 0000000000..ebc1ebbf01
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js
@@ -0,0 +1,30 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateuntil
+description: TypeError thrown if timeZone.getOffsetNanosecondsFor is not callable
+features: [BigInt, Symbol, Temporal, arrow-function]
+---*/
+
+[undefined, null, true, Math.PI, 'string', Symbol('sym'), 42n, {}].forEach((notCallable) => {
+ const timeZone = new Temporal.TimeZone("UTC");
+ const calendar = new Temporal.Calendar("iso8601");
+ const date = new Temporal.PlainDate(2000, 5, 2);
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ timeZone.getOffsetNanosecondsFor = notCallable;
+
+ assert.throws(
+ TypeError,
+ () => calendar.dateUntil(datetime, date),
+ `Uncallable ${notCallable === null ? 'null' : typeof notCallable} getOffsetNanosecondsFor should throw TypeError`
+ );
+ assert.throws(
+ TypeError,
+ () => calendar.dateUntil(date, datetime),
+ `Uncallable ${notCallable === null ? 'null' : typeof notCallable} getOffsetNanosecondsFor should throw TypeError`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js
new file mode 100644
index 0000000000..ff81410145
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js
@@ -0,0 +1,22 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateuntil
+description: RangeError thrown if time zone reports an offset that is out of range
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+[-86400_000_000_000, 86400_000_000_000].forEach((wrongOffset) => {
+ const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset);
+ const calendar = new Temporal.Calendar("iso8601");
+ const date = new Temporal.PlainDate(2000, 5, 2);
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+
+ assert.throws(RangeError, () => calendar.dateUntil(datetime, date));
+ assert.throws(RangeError, () => calendar.dateUntil(date, datetime));
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js
new file mode 100644
index 0000000000..446a1a6ea3
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js
@@ -0,0 +1,31 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateuntil
+description: TypeError thrown if time zone reports an offset that is not a Number
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+[
+ undefined,
+ null,
+ true,
+ "+01:00",
+ Symbol(),
+ 3600_000_000_000n,
+ {},
+ { valueOf() { return 3600_000_000_000; } },
+].forEach((wrongOffset) => {
+ const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset);
+ const calendar = new Temporal.Calendar("iso8601");
+ const date = new Temporal.PlainDate(2000, 5, 2);
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+
+ assert.throws(TypeError, () => calendar.dateUntil(datetime, date));
+ assert.throws(TypeError, () => calendar.dateUntil(date, datetime));
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/basic.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/basic.js
new file mode 100644
index 0000000000..99f4e9059b
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/basic.js
@@ -0,0 +1,48 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateuntil
+description: Basic tests for dateUntil().
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const iso = Temporal.Calendar.from("iso8601");
+const date1 = Temporal.PlainDate.from("1999-09-03");
+const date2 = Temporal.PlainDate.from("2000-01-01");
+
+TemporalHelpers.assertDuration(
+ iso.dateUntil(date1, date2, {}),
+ 0, 0, 0, 120, 0, 0, 0, 0, 0, 0, "two PlainDates");
+
+TemporalHelpers.assertDuration(
+ iso.dateUntil(Temporal.PlainDateTime.from("1999-09-03T08:15:30"), date2, {}),
+ 0, 0, 0, 120, 0, 0, 0, 0, 0, 0, "first argument: PlainDateTime");
+
+TemporalHelpers.assertDuration(
+ iso.dateUntil({ year: 1999, month: 9, day: 3 }, date2, {}),
+ 0, 0, 0, 120, 0, 0, 0, 0, 0, 0, "first argument: property bag");
+
+TemporalHelpers.assertDuration(
+ iso.dateUntil("1999-09-03", date2, {}),
+ 0, 0, 0, 120, 0, 0, 0, 0, 0, 0, "first argument: string");
+
+assert.throws(TypeError, () => iso.dateUntil({ month: 11 }, date2, {}), "first argument: missing property");
+
+TemporalHelpers.assertDuration(
+ iso.dateUntil(date1, Temporal.PlainDateTime.from("2000-01-01T08:15:30"), {}),
+ 0, 0, 0, 120, 0, 0, 0, 0, 0, 0, "second argument: PlainDateTime");
+
+TemporalHelpers.assertDuration(
+ iso.dateUntil(date1, { year: 2000, month: 1, day: 1 }, {}),
+ 0, 0, 0, 120, 0, 0, 0, 0, 0, 0, "second argument: property bag");
+
+TemporalHelpers.assertDuration(
+ iso.dateUntil(date1, "2000-01-01", {}),
+ 0, 0, 0, 120, 0, 0, 0, 0, 0, 0, "second argument: string");
+
+assert.throws(TypeError, () => iso.dateUntil(date1, { month: 11 }, {}), "second argument: missing property");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/branding.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/branding.js
new file mode 100644
index 0000000000..ea4dec80e6
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/branding.js
@@ -0,0 +1,27 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateuntil
+description: Throw a TypeError if the receiver is invalid
+features: [Symbol, Temporal]
+---*/
+
+const dateUntil = Temporal.Calendar.prototype.dateUntil;
+
+assert.sameValue(typeof dateUntil, "function");
+
+const args = [new Temporal.PlainDate(2021, 7, 16), new Temporal.PlainDate(2021, 7, 17)];
+
+assert.throws(TypeError, () => dateUntil.apply(undefined, args), "undefined");
+assert.throws(TypeError, () => dateUntil.apply(null, args), "null");
+assert.throws(TypeError, () => dateUntil.apply(true, args), "true");
+assert.throws(TypeError, () => dateUntil.apply("", args), "empty string");
+assert.throws(TypeError, () => dateUntil.apply(Symbol(), args), "symbol");
+assert.throws(TypeError, () => dateUntil.apply(1, args), "1");
+assert.throws(TypeError, () => dateUntil.apply({}, args), "plain object");
+assert.throws(TypeError, () => dateUntil.apply(Temporal.Calendar, args), "Temporal.Calendar");
+assert.throws(TypeError, () => dateUntil.apply(Temporal.Calendar.prototype, args), "Temporal.Calendar.prototype");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/browser.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/browser.js
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/builtin.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/builtin.js
new file mode 100644
index 0000000000..9cc12208df
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/builtin.js
@@ -0,0 +1,36 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateuntil
+description: >
+ Tests that Temporal.Calendar.prototype.dateUntil
+ meets the requirements for built-in objects defined by the
+ introduction of chapter 17 of the ECMAScript Language Specification.
+info: |
+ Built-in functions that are not constructors do not have a "prototype" property unless
+ otherwise specified in the description of a particular function.
+
+ Unless specified otherwise, a built-in object that is callable as a function is a built-in
+ function object with the characteristics described in 10.3. Unless specified otherwise, the
+ [[Extensible]] internal slot of a built-in object initially has the value true.
+
+ Unless otherwise specified every built-in function and every built-in constructor has the
+ Function prototype object [...] as the value of its [[Prototype]] internal slot.
+features: [Temporal]
+---*/
+
+assert.sameValue(Object.isExtensible(Temporal.Calendar.prototype.dateUntil),
+ true, "Built-in objects must be extensible.");
+
+assert.sameValue(Object.prototype.toString.call(Temporal.Calendar.prototype.dateUntil),
+ "[object Function]", "Object.prototype.toString");
+
+assert.sameValue(Object.getPrototypeOf(Temporal.Calendar.prototype.dateUntil),
+ Function.prototype, "prototype");
+
+assert.sameValue(Temporal.Calendar.prototype.dateUntil.hasOwnProperty("prototype"),
+ false, "prototype property");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/calendar-datefromfields-called-with-options-undefined.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/calendar-datefromfields-called-with-options-undefined.js
new file mode 100644
index 0000000000..cc19ddb323
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/calendar-datefromfields-called-with-options-undefined.js
@@ -0,0 +1,18 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateuntil
+description: >
+ Calendar.dateFromFields method is called with undefined as the options value
+ when call originates internally
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions();
+calendar.dateUntil({ year: 2000, month: 5, day: 2, calendar }, { year: 2000, month: 5, day: 3, calendar });
+assert.sameValue(calendar.dateFromFieldsCallCount, 2);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/calendar-fields-iterable.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/calendar-fields-iterable.js
new file mode 100644
index 0000000000..dc32b6b936
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/calendar-fields-iterable.js
@@ -0,0 +1,43 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateuntil
+description: Verify the result of calendar.fields() is treated correctly.
+info: |
+ sec-temporal.calendar.prototype.dateuntil steps 4–5:
+ 4. Set _one_ to ? ToTemporalDate(_one_).
+ 5. Set _two_ to ? ToTemporalDate(_two_).
+ sec-temporal-totemporaldate step 2.c:
+ c. Let _fieldNames_ be ? CalendarFields(_calendar_, « *"day"*, *"month"*, *"monthCode"*, *"year"* »).
+ sec-temporal-calendarfields step 4:
+ 4. Let _result_ be ? IterableToListOfType(_fieldsArray_, « String »).
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const expected = [
+ "day",
+ "month",
+ "monthCode",
+ "year",
+];
+
+const calendar1 = TemporalHelpers.calendarFieldsIterable();
+const calendar2 = TemporalHelpers.calendarFieldsIterable();
+const calendar3 = TemporalHelpers.calendarFieldsIterable();
+calendar1.dateUntil(
+ { year: 2000, month: 5, day: 2, calendar: calendar2 },
+ { year: 2005, month: 6, day: 3, calendar: calendar3 },
+);
+
+assert.sameValue(calendar1.fieldsCallCount, 0, "fields() method not called");
+assert.sameValue(calendar2.fieldsCallCount, 1, "fields() method called once");
+assert.sameValue(calendar3.fieldsCallCount, 1, "fields() method called once");
+assert.compareArray(calendar2.fieldsCalledWith[0], expected, "fields() method called with correct args");
+assert(calendar2.iteratorExhausted[0], "iterated through the whole iterable");
+assert.compareArray(calendar3.fieldsCalledWith[0], expected, "fields() method called with correct args");
+assert(calendar3.iteratorExhausted[0], "iterated through the whole iterable");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/calendar-temporal-object.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/calendar-temporal-object.js
new file mode 100644
index 0000000000..a42cf66f0a
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/calendar-temporal-object.js
@@ -0,0 +1,33 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateuntil
+description: Fast path for converting other Temporal objects to Temporal.Calendar by reading internal slots
+info: |
+ sec-temporal.calendar.prototype.dateuntil steps 4–5:
+ 4. Set _one_ to ? ToTemporalDate(_one_).
+ 5. Set _two_ to ? ToTemporalDate(_two_).
+ sec-temporal-totemporaldate step 2.c:
+ c. Let _calendar_ be ? GetTemporalCalendarWithISODefault(_item_).
+ sec-temporal-gettemporalcalendarwithisodefault step 2:
+ 2. Return ? ToTemporalCalendarWithISODefault(_calendar_).
+ sec-temporal-totemporalcalendarwithisodefault step 2:
+ 3. Return ? ToTemporalCalendar(_temporalCalendarLike_).
+ sec-temporal-totemporalcalendar step 1.a:
+ a. If _temporalCalendarLike_ has an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]], [[InitializedTemporalMonthDay]], [[InitializedTemporalYearMonth]], or [[InitializedTemporalZonedDateTime]] internal slot, then
+ i. Return _temporalCalendarLike_.[[Calendar]].
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+TemporalHelpers.checkToTemporalCalendarFastPath((temporalObject) => {
+ const calendar = new Temporal.Calendar("iso8601");
+ calendar.dateUntil(
+ { year: 2000, month: 5, day: 2, calendar: temporalObject },
+ { year: 2005, month: 6, day: 3, calendar: temporalObject },
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/largest-unit-day.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/largest-unit-day.js
new file mode 100644
index 0000000000..5d5aaecbb9
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/largest-unit-day.js
@@ -0,0 +1,62 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateuntil
+description: Temporal.Calendar.prototype.dateUntil with largestUnit is "day"
+info: |
+ 1. Let calendar be the this value.
+ 2. Perform ? RequireInternalSlot(calendar, [[InitializedTemporalCalendar]]).
+ 3. Assert: calendar.[[Identifier]] is "iso8601".
+ 4. Set one to ? ToTemporalDate(one).
+ 5. Set two to ? ToTemporalDate(two).
+ 6. Set options to ? GetOptionsObject(options).
+ 7. Let largestUnit be ? ToLargestTemporalUnit(options, « "hour", "minute", "second", "millisecond", "microsecond", "nanosecond" », "auto", "day").
+ 8. Let result be ! DifferenceISODate(one.[[ISOYear]], one.[[ISOMonth]], one.[[ISODay]], two.[[ISOYear]], two.[[ISOMonth]], two.[[ISODay]], largestUnit).
+ 9. Return ? CreateTemporalDuration(result.[[Years]], result.[[Months]], result.[[Weeks]], result.[[Days]], 0, 0, 0, 0, 0, 0).
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+["day", "days"].forEach(function(largestUnit) {
+ let opt = {largestUnit};
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-16", "2021-07-16", opt),
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "same day");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-16", "2021-07-17", opt),
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, "one day");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-16", "2021-08-17", opt),
+ 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, "32 days");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-16", "2021-09-16", opt),
+ 0, 0, 0, 62, 0, 0, 0, 0, 0, 0, "62 days");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-16", "2022-07-16", opt),
+ 0, 0, 0, 365, 0, 0, 0, 0, 0, 0, "365 days");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-16", "2031-07-16", opt),
+ 0, 0, 0, 3652, 0, 0, 0, 0, 0, 0, "3652 days");
+
+
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-17", "2021-07-16", opt),
+ 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, "negative one day");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-08-17", "2021-07-16", opt),
+ 0, 0, 0, -32, 0, 0, 0, 0, 0, 0, "negative 32 days");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-09-16", "2021-07-16", opt),
+ 0, 0, 0, -62, 0, 0, 0, 0, 0, 0, "negative 62 days");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2022-07-16", "2021-07-16", opt),
+ 0, 0, 0, -365, 0, 0, 0, 0, 0, 0, "negative 365 days");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2031-07-16", "2021-07-16", opt),
+ 0, 0, 0, -3652, 0, 0, 0, 0, 0, 0, "negative 3652 days");
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/largest-unit-month.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/largest-unit-month.js
new file mode 100644
index 0000000000..127391dc73
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/largest-unit-month.js
@@ -0,0 +1,97 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateuntil
+description: Temporal.Calendar.prototype.dateUntil with largestUnit is "month"
+info: |
+ 1. Let calendar be the this value.
+ 2. Perform ? RequireInternalSlot(calendar, [[InitializedTemporalCalendar]]).
+ 3. Assert: calendar.[[Identifier]] is "iso8601".
+ 4. Set one to ? ToTemporalDate(one).
+ 5. Set two to ? ToTemporalDate(two).
+ 6. Set options to ? GetOptionsObject(options).
+ 7. Let largestUnit be ? ToLargestTemporalUnit(options, « "hour", "minute", "second", "millisecond", "microsecond", "nanosecond" », "auto", "day").
+ 8. Let result be ! DifferenceISODate(one.[[ISOYear]], one.[[ISOMonth]], one.[[ISODay]], two.[[ISOYear]], two.[[ISOMonth]], two.[[ISODay]], largestUnit).
+ 9. Return ? CreateTemporalDuration(result.[[Years]], result.[[Months]], result.[[Weeks]], result.[[Days]], 0, 0, 0, 0, 0, 0).
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+["month", "months"].forEach(function(largestUnit) {
+ let opt = {largestUnit};
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-16", "2021-07-16", opt),
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "same day");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-16", "2021-07-17", opt),
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, "one day");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-16", "2021-07-23", opt),
+ 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, "7 days");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-16", "2021-08-16", opt),
+ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, "1 month in same year");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2020-12-16", "2021-01-16", opt),
+ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, "1 month in different year");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-01-05", "2021-02-05", opt),
+ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, "1 month in same year");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-01-07", "2021-03-07", opt),
+ 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, "2 month in same year across Feb 28");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-16", "2021-08-17", opt),
+ 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, "1 month and 1 day in a month with 31 days");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-16", "2021-08-13", opt),
+ 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, "28 days roll across a month which has 31 days");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-16", "2021-09-16", opt),
+ 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, "2 months with both months which have 31 days");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-16", "2022-07-16", opt),
+ 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, "12 months");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-16", "2031-07-16", opt),
+ 0, 120, 0, 0, 0, 0, 0, 0, 0, 0, "120 months");
+
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-17", "2021-07-16", opt),
+ 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, "negative one day");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-23", "2021-07-16", opt),
+ 0, 0, 0, -7, 0, 0, 0, 0, 0, 0, "negative 7 days");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-08-16", "2021-07-16", opt),
+ 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, "negative 1 month in same year");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-01-16", "2020-12-16", opt),
+ 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, "negative 1 month in different year");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-02-05", "2021-01-05", opt),
+ 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, "negative 1 month in same year");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-03-07", "2021-01-07", opt),
+ 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, "negative 2 month in same year across Feb 28");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-08-17", "2021-07-16", opt),
+ 0, -1, 0, -1, 0, 0, 0, 0, 0, 0, "negative 1 month and 1 day in a month with 31 days");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-08-13", "2021-07-16", opt),
+ 0, 0, 0, -28, 0, 0, 0, 0, 0, 0, "negative 28 days roll across a month which has 31 days");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-09-16", "2021-07-16", opt),
+ 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, "negative 2 months with both months which have 31 days");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2022-07-16", "2021-07-16", opt),
+ 0, -12, 0, 0, 0, 0, 0, 0, 0, 0, "negative 12 months");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2031-07-16", "2021-07-16", opt),
+ 0, -120, 0, 0, 0, 0, 0, 0, 0, 0, "negative 120 months");
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/largest-unit-week.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/largest-unit-week.js
new file mode 100644
index 0000000000..c3bf258482
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/largest-unit-week.js
@@ -0,0 +1,74 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateuntil
+description: Temporal.Calendar.prototype.dateUntil with largestUnit is "week"
+info: |
+ 1. Let calendar be the this value.
+ 2. Perform ? RequireInternalSlot(calendar, [[InitializedTemporalCalendar]]).
+ 3. Assert: calendar.[[Identifier]] is "iso8601".
+ 4. Set one to ? ToTemporalDate(one).
+ 5. Set two to ? ToTemporalDate(two).
+ 6. Set options to ? GetOptionsObject(options).
+ 7. Let largestUnit be ? ToLargestTemporalUnit(options, « "hour", "minute", "second", "millisecond", "microsecond", "nanosecond" », "auto", "day").
+ 8. Let result be ! DifferenceISODate(one.[[ISOYear]], one.[[ISOMonth]], one.[[ISODay]], two.[[ISOYear]], two.[[ISOMonth]], two.[[ISODay]], largestUnit).
+ 9. Return ? CreateTemporalDuration(result.[[Years]], result.[[Months]], result.[[Weeks]], result.[[Days]], 0, 0, 0, 0, 0, 0).
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+["week", "weeks"].forEach(function(largestUnit) {
+ let opt = {largestUnit};
+
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-16", "2021-07-16", opt),
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "same day");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-16", "2021-07-17", opt),
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, "one day");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-16", "2021-07-23", opt),
+ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, "7 days");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-16", "2021-08-16", opt),
+ 0, 0, 4, 3, 0, 0, 0, 0, 0, 0, "4 weeks and 3 days");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-16", "2021-08-13", opt),
+ 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, "4 weeks");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-16", "2021-09-16", opt),
+ 0, 0, 8, 6, 0, 0, 0, 0, 0, 0, "8 weeks and 6 days");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-16", "2022-07-16", opt),
+ 0, 0, 52, 1, 0, 0, 0, 0, 0, 0, "52 weeks and 1 day");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-16", "2031-07-16", opt),
+ 0, 0, 521, 5, 0, 0, 0, 0, 0, 0, "521 weeks and 5 days");
+
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-17", "2021-07-16", opt),
+ 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, "negative one day");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-23", "2021-07-16", opt),
+ 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, "negative 7 days");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-08-16", "2021-07-16", opt),
+ 0, 0, -4, -3, 0, 0, 0, 0, 0, 0, "negative 4 weeks and 3 days");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-08-13", "2021-07-16", opt),
+ 0, 0, -4, 0, 0, 0, 0, 0, 0, 0, "negative 4 weeks");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-09-16", "2021-07-16", opt),
+ 0, 0, -8, -6, 0, 0, 0, 0, 0, 0, "negative 8 weeks and 6 days");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2022-07-16", "2021-07-16", opt),
+ 0, 0, -52, -1, 0, 0, 0, 0, 0, 0, "negative 52 weeks and 1 day");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2031-07-16", "2021-07-16", opt),
+ 0, 0, -521, -5, 0, 0, 0, 0, 0, 0, "negative 521 weeks and 5 days");
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/largest-unit-year.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/largest-unit-year.js
new file mode 100644
index 0000000000..fb29a8c493
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/largest-unit-year.js
@@ -0,0 +1,207 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateuntil
+description: Temporal.Calendar.prototype.dateUntil with largestUnit is "year"
+info: |
+ 1. Let calendar be the this value.
+ 2. Perform ? RequireInternalSlot(calendar, [[InitializedTemporalCalendar]]).
+ 3. Assert: calendar.[[Identifier]] is "iso8601".
+ 4. Set one to ? ToTemporalDate(one).
+ 5. Set two to ? ToTemporalDate(two).
+ 6. Set options to ? GetOptionsObject(options).
+ 7. Let largestUnit be ? ToLargestTemporalUnit(options, « "hour", "minute", "second", "millisecond", "microsecond", "nanosecond" », "auto", "day").
+ 8. Let result be ! DifferenceISODate(one.[[ISOYear]], one.[[ISOMonth]], one.[[ISODay]], two.[[ISOYear]], two.[[ISOMonth]], two.[[ISODay]], largestUnit).
+ 9. Return ? CreateTemporalDuration(result.[[Years]], result.[[Months]], result.[[Weeks]], result.[[Days]], 0, 0, 0, 0, 0, 0).
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+["year", "years"].forEach(function(largestUnit) {
+ let opt = {largestUnit};
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-16", "2021-07-16", opt),
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "same day");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-16", "2021-07-17", opt),
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, "one day");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-16", "2021-07-23", opt),
+ 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, "7 days");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-16", "2021-08-16", opt),
+ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, "1 month in same year");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2020-12-16", "2021-01-16", opt),
+ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, "1 month in different year");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-01-05", "2021-02-05", opt),
+ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, "1 month in same year");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-01-07", "2021-03-07", opt),
+ 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, "2 month in same year across Feb 28");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-16", "2021-08-17", opt),
+ 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, "1 month and 1 day in a month with 31 days");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-16", "2021-08-13", opt),
+ 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, "28 days roll across a month which has 31 days");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-16", "2021-09-16", opt),
+ 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, "2 months with both months which have 31 days");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-16", "2022-07-16", opt),
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, "1 year");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-16", "2031-07-16", opt),
+ 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, "10 years");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-16", "2022-07-19", opt),
+ 1, 0, 0, 3, 0, 0, 0, 0, 0, 0, "1 year and 3 days");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-16", "2022-09-19", opt),
+ 1, 2, 0, 3, 0, 0, 0, 0, 0, 0, "1 year 2 months and 3 days");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-16", "2031-12-16", opt),
+ 10, 5, 0, 0, 0, 0, 0, 0, 0, 0, "10 years and 5 months");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("1997-12-16", "2021-07-16", opt),
+ 23, 7, 0, 0, 0, 0, 0, 0, 0, 0, "23 years and 7 months");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("1997-07-16", "2021-07-16", opt),
+ 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, "24 years");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("1997-07-16", "2021-07-15", opt),
+ 23, 11, 0, 29, 0, 0, 0, 0, 0, 0, "23 years, 11 months and 29 days");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("1997-06-16", "2021-06-15", opt),
+ 23, 11, 0, 30, 0, 0, 0, 0, 0, 0, "23 years, 11 months and 30 days");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("1960-02-16", "2020-03-16", opt),
+ 60, 1, 0, 0, 0, 0, 0, 0, 0, 0, "60 years, 1 month");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("1960-02-16", "2021-03-15", opt),
+ 61, 0, 0, 27, 0, 0, 0, 0, 0, 0, "61 years, 27 days in non leap year");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("1960-02-16", "2020-03-15", opt),
+ 60, 0, 0, 28, 0, 0, 0, 0, 0, 0, "60 years, 28 days in leap year");
+
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-03-30", "2021-07-16", opt),
+ 0, 3, 0, 16, 0, 0, 0, 0, 0, 0, "3 months and 16 days");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2020-03-30", "2021-07-16", opt),
+ 1, 3, 0, 16, 0, 0, 0, 0, 0, 0, "1 year, 3 months and 16 days");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("1960-03-30", "2021-07-16", opt),
+ 61, 3, 0, 16, 0, 0, 0, 0, 0, 0, "61 years, 3 months and 16 days");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2019-12-30", "2021-07-16", opt),
+ 1, 6, 0, 16, 0, 0, 0, 0, 0, 0, "1 year, 6 months and 16 days");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2020-12-30", "2021-07-16", opt),
+ 0, 6, 0, 16, 0, 0, 0, 0, 0, 0, "6 months and 16 days");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("1997-12-30", "2021-07-16", opt),
+ 23, 6, 0, 16, 0, 0, 0, 0, 0, 0, "23 years, 6 months and 16 days");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("0001-12-25", "2021-07-16", opt),
+ 2019, 6, 0, 21, 0, 0, 0, 0, 0, 0, "2019 years, 6 months and 21 days");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2019-12-30", "2021-03-05", opt),
+ 1, 2, 0, 5, 0, 0, 0, 0, 0, 0, "1 year, 2 months and 5 days");
+
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-17", "2021-07-16", opt),
+ 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, "negative one day");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-23", "2021-07-16", opt),
+ 0, 0, 0, -7, 0, 0, 0, 0, 0, 0, "negative 7 days");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-08-16", "2021-07-16", opt),
+ 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, "negative 1 month in same year");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-01-16", "2020-12-16", opt),
+ 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, "negative 1 month in different year");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-02-05", "2021-01-05", opt),
+ 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, "negative 1 month in same year");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-03-07", "2021-01-07", opt),
+ 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, "negative 2 month in same year across Feb 28");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-08-17", "2021-07-16", opt),
+ 0, -1, 0, -1, 0, 0, 0, 0, 0, 0, "negative 1 month and 1 day in a month with 31 days");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-08-13", "2021-07-16", opt),
+ 0, 0, 0, -28, 0, 0, 0, 0, 0, 0, "negative 28 days roll across a month which has 31 days");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-09-16", "2021-07-16", opt),
+ 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, "negative 2 months with both months which have 31 days");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2022-07-16", "2021-07-16", opt),
+ -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, "negative 1 year");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2031-07-16", "2021-07-16", opt),
+ -10, 0, 0, 0, 0, 0, 0, 0, 0, 0, "negative 10 years");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2022-07-19", "2021-07-16", opt),
+ -1, 0, 0, -3, 0, 0, 0, 0, 0, 0, "negative 1 year and 3 days");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2022-09-19", "2021-07-16", opt),
+ -1, -2, 0, -3, 0, 0, 0, 0, 0, 0, "negative 1 year 2 months and 3 days");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2031-12-16", "2021-07-16", opt),
+ -10, -5, 0, 0, 0, 0, 0, 0, 0, 0, "negative 10 years and 5 months");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-16", "1997-12-16", opt),
+ -23, -7, 0, 0, 0, 0, 0, 0, 0, 0, "negative 23 years and 7 months");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-16", "1997-07-16", opt),
+ -24, 0, 0, 0, 0, 0, 0, 0, 0, 0, "negative 24 years");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-15", "1997-07-16", opt),
+ -23, -11, 0, -30, 0, 0, 0, 0, 0, 0, "negative 23 years, 11 months and 30 days");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-06-15", "1997-06-16", opt),
+ -23, -11, 0, -29, 0, 0, 0, 0, 0, 0, "negative 23 years, 11 months and 29 days");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2020-03-16", "1960-02-16", opt),
+ -60, -1, 0, 0, 0, 0, 0, 0, 0, 0, "negative 60 years, 1 month");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-03-15", "1960-02-16", opt),
+ -61, 0, 0, -28, 0, 0, 0, 0, 0, 0, "negative 61 years, 28 days in non leap year");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2020-03-15", "1960-02-16", opt),
+ -60, 0, 0, -28, 0, 0, 0, 0, 0, 0, "negative 60 years, 28 days in leap year");
+
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-16", "2021-03-30", opt),
+ 0, -3, 0, -17, 0, 0, 0, 0, 0, 0, "negative 3 months and 17 days");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-16", "2020-03-30", opt),
+ -1, -3, 0, -17, 0, 0, 0, 0, 0, 0, "negative 1 year, 3 months and 17 days");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-16", "1960-03-30", opt),
+ -61, -3, 0, -17, 0, 0, 0, 0, 0, 0, "negative 61 years, 3 months and 17 days");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-16", "2019-12-30", opt),
+ -1, -6, 0, -17, 0, 0, 0, 0, 0, 0, "negative 1 year, 6 months and 17 days");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-16", "2020-12-30", opt),
+ 0, -6, 0, -17, 0, 0, 0, 0, 0, 0, "negative 6 months and 17 days");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-16", "1997-12-30", opt),
+ -23, -6, 0, -17, 0, 0, 0, 0, 0, 0, "negative 23 years, 6 months and 17 days");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-16", "0001-12-25", opt),
+ -2019, -6, 0, -22, 0, 0, 0, 0, 0, 0, "negative 2019 years, 6 months and 22 days");
+ TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-03-05", "2019-12-30", opt),
+ -1, -2, 0, -6, 0, 0, 0, 0, 0, 0, "negative 1 year, 2 months and 6 days");
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/largestunit-plurals-accepted.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/largestunit-plurals-accepted.js
new file mode 100644
index 0000000000..097b975550
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/largestunit-plurals-accepted.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateuntil
+description: Plural units are accepted as well for the largestUnit option
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const earlier = new Temporal.PlainDate(2000, 5, 2);
+const later = new Temporal.PlainDate(2001, 6, 12);
+const calendar = new Temporal.Calendar("iso8601");
+const validUnits = [
+ "year",
+ "month",
+ "week",
+ "day",
+];
+TemporalHelpers.checkPluralUnitsAccepted((largestUnit) => calendar.dateUntil(earlier, later, { largestUnit }), validUnits);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/leap-second.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/leap-second.js
new file mode 100644
index 0000000000..e40554c226
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/leap-second.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateuntil
+description: Leap second is a valid ISO string for PlainDate
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+let arg = "2016-12-31T23:59:60";
+let result = instance.dateUntil(arg, new Temporal.PlainDate(2017, 1, 1));
+TemporalHelpers.assertDuration(result, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, "leap second is a valid ISO string for PlainDate (first argument)");
+result = instance.dateUntil(new Temporal.PlainDate(2017, 1, 1), arg);
+TemporalHelpers.assertDuration(result, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, "leap second is a valid ISO string for PlainDate (second argument)");
+
+arg = { year: 2016, month: 12, day: 31, hour: 23, minute: 59, second: 60 };
+result = instance.dateUntil(arg, new Temporal.PlainDate(2017, 1, 1));
+TemporalHelpers.assertDuration(result, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, "second: 60 is ignored in property bag for PlainDate (first argument)");
+result = instance.dateUntil(new Temporal.PlainDate(2017, 1, 1), arg);
+TemporalHelpers.assertDuration(result, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, "second: 60 is ignored in property bag for PlainDate (second argument)");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/length.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/length.js
new file mode 100644
index 0000000000..03ccddfc49
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/length.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2020 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateuntil
+description: Temporal.Calendar.prototype.dateUntil.length is 2
+info: |
+ Every built-in function object, including constructors, has a "length" property whose value is
+ an integer. Unless otherwise specified, this value is equal to the largest number of named
+ arguments shown in the subclause headings for the function description. Optional parameters
+ (which are indicated with brackets: [ ]) or rest parameters (which are shown using the form
+ «...name») are not included in the default argument count.
+
+ Unless otherwise specified, the "length" property of a built-in function object has the
+ attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+verifyProperty(Temporal.Calendar.prototype.dateUntil, "length", {
+ value: 2,
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/name.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/name.js
new file mode 100644
index 0000000000..653e2aee58
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/name.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateuntil
+description: Temporal.Calendar.prototype.dateUntil.name is "dateUntil".
+info: |
+ Every built-in function object, including constructors, that is not identified as an anonymous
+ function has a "name" property whose value is a String. Unless otherwise specified, this value
+ is the name that is given to the function in this specification.
+
+ Unless otherwise specified, the "name" property of a built-in function object, if it exists,
+ has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+verifyProperty(Temporal.Calendar.prototype.dateUntil, "name", {
+ value: "dateUntil",
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/no-options.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/no-options.js
new file mode 100644
index 0000000000..76e14a3ca2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/no-options.js
@@ -0,0 +1,59 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateuntil
+description: Temporal.Calendar.prototype.dateUntil with no options
+info: |
+ 1. Let calendar be the this value.
+ 2. Perform ? RequireInternalSlot(calendar, [[InitializedTemporalCalendar]]).
+ 3. Assert: calendar.[[Identifier]] is "iso8601".
+ 4. Set one to ? ToTemporalDate(one).
+ 5. Set two to ? ToTemporalDate(two).
+ 6. Set options to ? GetOptionsObject(options).
+ 7. Let largestUnit be ? ToLargestTemporalUnit(options, « "hour", "minute", "second", "millisecond", "microsecond", "nanosecond" », "auto", "day").
+ 8. Let result be ! DifferenceISODate(one.[[ISOYear]], one.[[ISOMonth]], one.[[ISODay]], two.[[ISOYear]], two.[[ISOMonth]], two.[[ISODay]], largestUnit).
+ 9. Return ? CreateTemporalDuration(result.[[Years]], result.[[Months]], result.[[Weeks]], result.[[Days]], 0, 0, 0, 0, 0, 0).
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-16", "2021-07-16"),
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "same day");
+TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-16", "2021-07-17"),
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, "one day");
+TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-16", "2021-08-17"),
+ 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, "32 days");
+TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-16", "2021-09-16"),
+ 0, 0, 0, 62, 0, 0, 0, 0, 0, 0, "62 days");
+TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-16", "2022-07-16"),
+ 0, 0, 0, 365, 0, 0, 0, 0, 0, 0, "365 days");
+TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-16", "2031-07-16"),
+ 0, 0, 0, 3652, 0, 0, 0, 0, 0, 0, "3652 days");
+
+
+TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-07-17", "2021-07-16"),
+ 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, "negative one day");
+TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-08-17", "2021-07-16"),
+ 0, 0, 0, -32, 0, 0, 0, 0, 0, 0, "negative 32 days");
+TemporalHelpers.assertDuration(
+ cal.dateUntil("2021-09-16", "2021-07-16"),
+ 0, 0, 0, -62, 0, 0, 0, 0, 0, 0, "negative 62 days");
+TemporalHelpers.assertDuration(
+ cal.dateUntil("2022-07-16", "2021-07-16"),
+ 0, 0, 0, -365, 0, 0, 0, 0, 0, 0, "negative 365 days");
+TemporalHelpers.assertDuration(
+ cal.dateUntil("2031-07-16", "2021-07-16"),
+ 0, 0, 0, -3652, 0, 0, 0, 0, 0, 0, "negative 3652 days");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/not-a-constructor.js
new file mode 100644
index 0000000000..af2b9d1165
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/not-a-constructor.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateuntil
+description: >
+ Temporal.Calendar.prototype.dateUntil does not implement [[Construct]], is not new-able
+info: |
+ Built-in function objects that are not identified as constructors do not implement the
+ [[Construct]] internal method unless otherwise specified in the description of a particular
+ function.
+includes: [isConstructor.js]
+features: [Reflect.construct, Temporal]
+---*/
+
+assert.throws(TypeError, () => {
+ new Temporal.Calendar.prototype.dateUntil();
+}, "Calling as constructor");
+
+assert.sameValue(isConstructor(Temporal.Calendar.prototype.dateUntil), false,
+ "isConstructor(Temporal.Calendar.prototype.dateUntil)");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/options-object.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/options-object.js
new file mode 100644
index 0000000000..003988ef80
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/options-object.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateuntil
+description: Empty or a function object may be used as options
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const result1 = instance.dateUntil(new Temporal.PlainDate(1976, 11, 18), new Temporal.PlainDate(1984, 5, 31), {});
+TemporalHelpers.assertDuration(
+ result1, 0, 0, 0, 2751, 0, 0, 0, 0, 0, 0,
+ "options may be an empty plain object"
+);
+
+const result2 = instance.dateUntil(new Temporal.PlainDate(1976, 11, 18), new Temporal.PlainDate(1984, 5, 31), () => {});
+TemporalHelpers.assertDuration(
+ result2, 0, 0, 0, 2751, 0, 0, 0, 0, 0, 0,
+ "options may be a function object"
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/options-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/options-wrong-type.js
new file mode 100644
index 0000000000..0bd2ca80fc
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/options-wrong-type.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateuntil
+description: TypeError thrown when options argument is a primitive
+features: [BigInt, Symbol, Temporal]
+---*/
+
+const badOptions = [
+ null,
+ true,
+ "some string",
+ Symbol(),
+ 1,
+ 2n,
+];
+
+const instance = new Temporal.Calendar("iso8601");
+for (const value of badOptions) {
+ assert.throws(TypeError, () => instance.dateUntil(new Temporal.PlainDate(1976, 11, 18), new Temporal.PlainDate(1984, 5, 31), value),
+ `TypeError on wrong options type ${typeof value}`);
+};
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/order-of-operations.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/order-of-operations.js
new file mode 100644
index 0000000000..3daaaa71fe
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/order-of-operations.js
@@ -0,0 +1,129 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateuntil
+description: Properties on an object passed to dateUntil() are accessed in the correct order
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const expected = [
+ // ToTemporalDate 1 → GetTemporalCalendarSlotValueWithISODefault
+ "get one.calendar",
+ "has one.calendar.dateAdd",
+ "has one.calendar.dateFromFields",
+ "has one.calendar.dateUntil",
+ "has one.calendar.day",
+ "has one.calendar.dayOfWeek",
+ "has one.calendar.dayOfYear",
+ "has one.calendar.daysInMonth",
+ "has one.calendar.daysInWeek",
+ "has one.calendar.daysInYear",
+ "has one.calendar.fields",
+ "has one.calendar.id",
+ "has one.calendar.inLeapYear",
+ "has one.calendar.mergeFields",
+ "has one.calendar.month",
+ "has one.calendar.monthCode",
+ "has one.calendar.monthDayFromFields",
+ "has one.calendar.monthsInYear",
+ "has one.calendar.weekOfYear",
+ "has one.calendar.year",
+ "has one.calendar.yearMonthFromFields",
+ "has one.calendar.yearOfWeek",
+ // lookup
+ "get one.calendar.dateFromFields",
+ "get one.calendar.fields",
+ // ToTemporalDate 1 → CalendarFields
+ "call one.calendar.fields",
+ // ToTemporalDate 1 → PrepareTemporalFields
+ "get one.day",
+ "get one.day.valueOf",
+ "call one.day.valueOf",
+ "get one.month",
+ "get one.month.valueOf",
+ "call one.month.valueOf",
+ "get one.monthCode",
+ "get one.monthCode.toString",
+ "call one.monthCode.toString",
+ "get one.year",
+ "get one.year.valueOf",
+ "call one.year.valueOf",
+ // ToTemporalDate 1 → CalendarDateFromFields
+ "call one.calendar.dateFromFields",
+ // ToTemporalDate 2 → GetTemporalCalendarSlotValueWithISODefault
+ "get two.calendar",
+ "has two.calendar.dateAdd",
+ "has two.calendar.dateFromFields",
+ "has two.calendar.dateUntil",
+ "has two.calendar.day",
+ "has two.calendar.dayOfWeek",
+ "has two.calendar.dayOfYear",
+ "has two.calendar.daysInMonth",
+ "has two.calendar.daysInWeek",
+ "has two.calendar.daysInYear",
+ "has two.calendar.fields",
+ "has two.calendar.id",
+ "has two.calendar.inLeapYear",
+ "has two.calendar.mergeFields",
+ "has two.calendar.month",
+ "has two.calendar.monthCode",
+ "has two.calendar.monthDayFromFields",
+ "has two.calendar.monthsInYear",
+ "has two.calendar.weekOfYear",
+ "has two.calendar.year",
+ "has two.calendar.yearMonthFromFields",
+ "has two.calendar.yearOfWeek",
+ // lookup
+ "get two.calendar.dateFromFields",
+ "get two.calendar.fields",
+ // ToTemporalDate 2 → CalendarFields
+ "call two.calendar.fields",
+ // ToTemporalDate 2 → PrepareTemporalFields
+ "get two.day",
+ "get two.day.valueOf",
+ "call two.day.valueOf",
+ "get two.month",
+ "get two.month.valueOf",
+ "call two.month.valueOf",
+ "get two.monthCode",
+ "get two.monthCode.toString",
+ "call two.monthCode.toString",
+ "get two.year",
+ "get two.year.valueOf",
+ "call two.year.valueOf",
+ // ToTemporalDate 2 → CalendarDateFromFields
+ "call two.calendar.dateFromFields",
+ // GetTemporalUnit
+ "get options.largestUnit",
+ "get options.largestUnit.toString",
+ "call options.largestUnit.toString",
+];
+const actual = [];
+
+const instance = new Temporal.Calendar("iso8601");
+
+const one = TemporalHelpers.propertyBagObserver(actual, {
+ year: 2000,
+ month: 5,
+ monthCode: "M05",
+ day: 2,
+ calendar: TemporalHelpers.calendarObserver(actual, "one.calendar"),
+}, "one");
+
+const two = TemporalHelpers.propertyBagObserver(actual, {
+ year: 2001,
+ month: 10,
+ monthCode: "M10",
+ day: 4,
+ calendar: TemporalHelpers.calendarObserver(actual, "two.calendar"),
+}, "two");
+
+const options = TemporalHelpers.propertyBagObserver(actual, { largestUnit: "day" }, "options");
+
+instance.dateUntil(one, two, options);
+assert.compareArray(actual, expected, "order of operations");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/prop-desc.js
new file mode 100644
index 0000000000..ca1c358c89
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/prop-desc.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateuntil
+description: The "dateUntil" property of Temporal.Calendar.prototype
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+assert.sameValue(
+ typeof Temporal.Calendar.prototype.dateUntil,
+ "function",
+ "`typeof Calendar.prototype.dateUntil` is `function`"
+);
+
+verifyProperty(Temporal.Calendar.prototype, "dateUntil", {
+ writable: true,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/shell.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/shell.js
new file mode 100644
index 0000000000..eda1477282
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/shell.js
@@ -0,0 +1,24 @@
+// GENERATED, DO NOT EDIT
+// file: isConstructor.js
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: |
+ Test if a given function is a constructor function.
+defines: [isConstructor]
+features: [Reflect.construct]
+---*/
+
+function isConstructor(f) {
+ if (typeof f !== "function") {
+ throw new Test262Error("isConstructor invoked with a non-function value");
+ }
+
+ try {
+ Reflect.construct(function(){}, [], f);
+ } catch (e) {
+ return false;
+ }
+ return true;
+}
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/throws-range-error-ToLargestTemporalUnit.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/throws-range-error-ToLargestTemporalUnit.js
new file mode 100644
index 0000000000..1934d14874
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/throws-range-error-ToLargestTemporalUnit.js
@@ -0,0 +1,20 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateuntil
+description: Temporal.Calendar.prototype.dateUntil throw RangeError on ToLargestTemporalUnit with invalide or disallowed unit
+info: |
+ 7. Let largestUnit be ? ToLargestTemporalUnit(options, « "hour", "minute", "second", "millisecond", "microsecond", "nanosecond" », "auto", "day").
+features: [Temporal, arrow-function]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+["invalid", "hour", "minute", "second", "millisecond", "microsecond",
+ "nanosecond"].forEach(function(largestUnit) {
+ assert.throws(RangeError, () => cal.dateUntil("2021-07-16", "2022-03-04", {largestUnit}),
+ 'cal.dateUntil("2021-07-16", "2022-03-04", {largestUnit}) throws a RangeError exception');
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/throws-range-error-ToTemporalDate.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/throws-range-error-ToTemporalDate.js
new file mode 100644
index 0000000000..f67da59b3e
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/throws-range-error-ToTemporalDate.js
@@ -0,0 +1,21 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateuntil
+description: Temporal.Calendar.prototype.dateUntil throw RangeError on ToTemporalDate
+info: |
+ 1. Let calendar be the this value.
+ 4. Set one to ? ToTemporalDate(one).
+ 5. Set two to ? ToTemporalDate(two).
+features: [Temporal, arrow-function]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+assert.throws(RangeError, () => cal.dateUntil("2021-07-16", "invalide date"),
+ 'cal.dateUntil("2021-07-16", "invalide date") throws a RangeError exception');
+assert.throws(RangeError, () => cal.dateUntil("invalide date", "2021-07-16"),
+ 'cal.dateUntil("invalide date", "2021-07-16") throws a RangeError exception');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/throws-type-error-GetOptionsObject.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/throws-type-error-GetOptionsObject.js
new file mode 100644
index 0000000000..cb98140f26
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/throws-type-error-GetOptionsObject.js
@@ -0,0 +1,21 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.dateuntil
+description: Temporal.Calendar.prototype.dateUntil throw TypeError on GetOptionsObject
+info: |
+ 6. Set options to ? GetOptionsObject(options).
+features: [BigInt, Symbol, Temporal, arrow-function]
+---*/
+let cal = new Temporal.Calendar('iso8601');
+
+['string', null, true, false, 123, 456n, Symbol(), Infinity, NaN].forEach(function(opt) {
+ assert.throws(
+ TypeError,
+ () => cal.dateUntil('2021-07-16', '2021-08-11', opt),
+ 'cal.dateUntil("2021-07-16", "2021-08-11", opt) throws a TypeError exception'
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/year-zero.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/year-zero.js
new file mode 100644
index 0000000000..16009d4b8d
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dateUntil/year-zero.js
@@ -0,0 +1,34 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dateuntil
+description: Negative zero, as extended year, is invalid
+features: [Temporal]
+---*/
+
+const calendar = new Temporal.Calendar("iso8601");
+const date = new Temporal.PlainDate(2000, 5, 2);
+const invalidStrings = [
+ "-000000-10-31",
+ "-000000-10-31T00:45",
+ "-000000-10-31T00:45+01:00",
+ "-000000-10-31T00:45+00:00[UTC]",
+];
+
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => calendar.dateUntil(arg, date),
+ "cannot use minus zero as extended date (first argument)"
+ );
+
+ assert.throws(
+ RangeError,
+ () => calendar.dateUntil(date, arg),
+ "cannot use minus zero as extended date (second argument)"
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-builtin-calendar-no-array-iteration.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-builtin-calendar-no-array-iteration.js
new file mode 100644
index 0000000000..9b0728c95d
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-builtin-calendar-no-array-iteration.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.day
+description: >
+ Calling the method with a property bag argument with a builtin calendar causes
+ no observable array iteration when getting the calendar fields.
+features: [Temporal]
+---*/
+
+const arrayPrototypeSymbolIteratorOriginal = Array.prototype[Symbol.iterator];
+Array.prototype[Symbol.iterator] = function arrayIterator() {
+ throw new Test262Error("Array should not be iterated");
+}
+
+const instance = new Temporal.Calendar("iso8601");
+const arg = { year: 2000, month: 5, day: 2, calendar: "iso8601" };
+instance.day(arg);
+
+Array.prototype[Symbol.iterator] = arrayPrototypeSymbolIteratorOriginal;
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-calendar-datefromfields-called-with-null-prototype-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-calendar-datefromfields-called-with-null-prototype-fields.js
new file mode 100644
index 0000000000..7238a8789b
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-calendar-datefromfields-called-with-null-prototype-fields.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.day
+description: >
+ Calendar.dateFromFields method is called with a null-prototype fields object
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarCheckFieldsPrototypePollution();
+const instance = new Temporal.Calendar("iso8601");
+const arg = { year: 2000, month: 5, day: 2, calendar };
+instance.day(arg);
+assert.sameValue(calendar.dateFromFieldsCallCount, 1, "dateFromFields should be called on the property bag's calendar");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-constructor-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-constructor-in-calendar-fields.js
new file mode 100644
index 0000000000..9ba373f078
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-constructor-in-calendar-fields.js
@@ -0,0 +1,17 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.day
+description: If a calendar's fields() method returns a field named 'constructor', PrepareTemporalFields should throw a RangeError.
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarWithExtraFields(['constructor']);
+const arg = {year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar};
+const instance = new Temporal.Calendar("iso8601");
+
+assert.throws(RangeError, () => instance.day(arg));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-duplicate-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-duplicate-calendar-fields.js
new file mode 100644
index 0000000000..4a285f17fe
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-duplicate-calendar-fields.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.day
+description: If a calendar's fields() method returns duplicate field names, PrepareTemporalFields should throw a RangeError.
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+for (const extra_fields of [['foo', 'foo'], ['day'], ['month'], ['monthCode'], ['year']]) {
+ const calendar = TemporalHelpers.calendarWithExtraFields(extra_fields);
+ const arg = { year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar };
+ const instance = new Temporal.Calendar("iso8601");
+
+ assert.throws(RangeError, () => instance.day(arg));
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-leap-second.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-leap-second.js
new file mode 100644
index 0000000000..d8407aa8a4
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-leap-second.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.day
+description: Leap second is a valid ISO string for PlainDate
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+let arg = "2016-12-31T23:59:60";
+const result1 = instance.day(arg);
+assert.sameValue(
+ result1,
+ 31,
+ "leap second is a valid ISO string for PlainDate"
+);
+
+arg = { year: 2016, month: 12, day: 31, hour: 23, minute: 59, second: 60 };
+const result2 = instance.day(arg);
+assert.sameValue(
+ result2,
+ 31,
+ "second: 60 is ignored in property bag for PlainDate"
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-number.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-number.js
new file mode 100644
index 0000000000..131c280ca7
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-number.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.day
+description: A number cannot be used in place of a Temporal.PlainDate
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const numbers = [
+ 1,
+ 19761118,
+ -19761118,
+ 1234567890,
+];
+
+for (const arg of numbers) {
+ assert.throws(
+ TypeError,
+ () => instance.day(arg),
+ 'Numbers cannot be used in place of an ISO string for PlainDate'
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-propertybag-calendar-case-insensitive.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-propertybag-calendar-case-insensitive.js
new file mode 100644
index 0000000000..0879d4d819
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-propertybag-calendar-case-insensitive.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.day
+description: The calendar name is case-insensitive
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const calendar = "IsO8601";
+
+const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+const result = instance.day(arg);
+assert.sameValue(result, 18, "Calendar is case-insensitive");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-propertybag-calendar-leap-second.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-propertybag-calendar-leap-second.js
new file mode 100644
index 0000000000..a1b5f9f765
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-propertybag-calendar-leap-second.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.day
+description: Leap second is a valid ISO string for a calendar in a property bag
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const calendar = "2016-12-31T23:59:60";
+
+const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+const result = instance.day(arg);
+assert.sameValue(
+ result,
+ 18,
+ "leap second is a valid ISO string for calendar"
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-propertybag-calendar-number.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-propertybag-calendar-number.js
new file mode 100644
index 0000000000..080af485a6
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-propertybag-calendar-number.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.day
+description: A number as calendar in a property bag is not accepted
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const numbers = [
+ 1,
+ 19970327,
+ -19970327,
+ 1234567890,
+];
+
+for (const calendar of numbers) {
+ const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+ assert.throws(
+ TypeError,
+ () => instance.day(arg),
+ "Numbers cannot be used as a calendar"
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-propertybag-calendar-string.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-propertybag-calendar-string.js
new file mode 100644
index 0000000000..e397d5ede6
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-propertybag-calendar-string.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.day
+description: A calendar ID is valid input for Calendar
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const calendar = "iso8601";
+
+const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+const result = instance.day(arg);
+assert.sameValue(result, 18, `Calendar created from string "${calendar}"`);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-propertybag-calendar-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-propertybag-calendar-wrong-type.js
new file mode 100644
index 0000000000..cef7b6ff05
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-propertybag-calendar-wrong-type.js
@@ -0,0 +1,46 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.day
+description: >
+ Appropriate error thrown when a calendar property from a property bag cannot
+ be converted to a calendar object or string
+features: [BigInt, Symbol, Temporal]
+---*/
+
+const timeZone = new Temporal.TimeZone("UTC");
+const instance = new Temporal.Calendar("iso8601");
+
+const primitiveTests = [
+ [null, "null"],
+ [true, "boolean"],
+ ["", "empty string"],
+ [1, "number that doesn't convert to a valid ISO string"],
+ [1n, "bigint"],
+];
+
+for (const [calendar, description] of primitiveTests) {
+ const arg = { year: 2019, monthCode: "M11", day: 1, calendar };
+ assert.throws(
+ typeof calendar === 'string' ? RangeError : TypeError,
+ () => instance.day(arg),
+ `${description} does not convert to a valid ISO string`
+ );
+}
+
+const typeErrorTests = [
+ [Symbol(), "symbol"],
+ [{}, "plain object that doesn't implement the protocol"],
+ [new Temporal.TimeZone("UTC"), "time zone instance"],
+ [Temporal.Calendar, "Temporal.Calendar, object"],
+ [Temporal.Calendar.prototype, "Temporal.Calendar.prototype, object"], // fails brand check in dateFromFields()
+];
+
+for (const [calendar, description] of typeErrorTests) {
+ const arg = { year: 2019, monthCode: "M11", day: 1, calendar };
+ assert.throws(TypeError, () => instance.day(arg), `${description} is not a valid property bag and does not convert to a string`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-propertybag-calendar-year-zero.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-propertybag-calendar-year-zero.js
new file mode 100644
index 0000000000..454c6a68de
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-propertybag-calendar-year-zero.js
@@ -0,0 +1,27 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.day
+description: Negative zero, as an extended year, is rejected
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ "-000000-10-31",
+ "-000000-10-31T17:45",
+ "-000000-10-31T17:45Z",
+ "-000000-10-31T17:45+01:00",
+ "-000000-10-31T17:45+00:00[UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.day(arg),
+ "reject minus zero as extended year"
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-proto-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-proto-in-calendar-fields.js
new file mode 100644
index 0000000000..eaf3311eba
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-proto-in-calendar-fields.js
@@ -0,0 +1,17 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.day
+description: If a calendar's fields() method returns a field named '__proto__', PrepareTemporalFields should throw a RangeError.
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarWithExtraFields(['__proto__']);
+const arg = {year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar};
+const instance = new Temporal.Calendar("iso8601");
+
+assert.throws(RangeError, () => instance.day(arg));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-string-calendar-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-string-calendar-annotation.js
new file mode 100644
index 0000000000..2272f0dd1d
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-string-calendar-annotation.js
@@ -0,0 +1,33 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.day
+description: Various forms of calendar annotation; critical flag has no effect
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02[u-ca=iso8601]", "without time or time zone"],
+ ["2000-05-02[UTC][u-ca=iso8601]", "with time zone and no time"],
+ ["2000-05-02T15:23[u-ca=iso8601]", "without time zone"],
+ ["2000-05-02T15:23[UTC][u-ca=iso8601]", "with time zone"],
+ ["2000-05-02T15:23[!u-ca=iso8601]", "with ! and no time zone"],
+ ["2000-05-02T15:23[UTC][!u-ca=iso8601]", "with ! and time zone"],
+ ["2000-05-02T15:23[u-ca=iso8601][u-ca=discord]", "second annotation ignored"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.day(arg);
+
+ assert.sameValue(
+ result,
+ 2,
+ `calendar annotation (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-string-critical-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-string-critical-unknown-annotation.js
new file mode 100644
index 0000000000..bbb53bca6a
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-string-critical-unknown-annotation.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.day
+description: Unknown annotations with critical flag are rejected
+features: [Temporal]
+---*/
+
+const invalidStrings = [
+ "1970-01-01[!foo=bar]",
+ "1970-01-01T00:00[!foo=bar]",
+ "1970-01-01T00:00[UTC][!foo=bar]",
+ "1970-01-01T00:00[u-ca=iso8601][!foo=bar]",
+ "1970-01-01T00:00[UTC][!foo=bar][u-ca=iso8601]",
+ "1970-01-01T00:00[foo=bar][!_foo-bar0=Dont-Ignore-This-99999999999]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.day(arg),
+ `reject unknown annotation with critical flag: ${arg}`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-string-date-with-utc-offset.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-string-date-with-utc-offset.js
new file mode 100644
index 0000000000..e6a0d706cd
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-string-date-with-utc-offset.js
@@ -0,0 +1,48 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.day
+description: UTC offset not valid with format that does not include a time
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const validStrings = [
+ "2000-05-02T00+00:00",
+ "2000-05-02T00+00:00[UTC]",
+ "2000-05-02T00+00:00[!UTC]",
+ "2000-05-02T00-02:30[America/St_Johns]",
+];
+
+for (const arg of validStrings) {
+ const result = instance.day(arg);
+
+ assert.sameValue(
+ result,
+ 2,
+ `"${arg}" is a valid UTC offset with time for PlainDate`
+ );
+}
+
+const invalidStrings = [
+ "2022-09-15Z",
+ "2022-09-15Z[UTC]",
+ "2022-09-15Z[Europe/Vienna]",
+ "2022-09-15+00:00",
+ "2022-09-15+00:00[UTC]",
+ "2022-09-15-02:30",
+ "2022-09-15-02:30[America/St_Johns]",
+];
+
+for (const arg of invalidStrings) {
+ assert.throws(
+ RangeError,
+ () => instance.day(arg),
+ `"${arg}" UTC offset without time is not valid for PlainDate`
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-string-invalid.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-string-invalid.js
new file mode 100644
index 0000000000..9b4cdb9bef
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-string-invalid.js
@@ -0,0 +1,64 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.day
+description: >
+ RangeError thrown if an invalid ISO string (or syntactically valid ISO string
+ that is not supported) is used as a PlainDate
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ // invalid ISO strings:
+ "",
+ "invalid iso8601",
+ "2020-01-00",
+ "2020-01-32",
+ "2020-02-30",
+ "2021-02-29",
+ "2020-00-01",
+ "2020-13-01",
+ "2020-01-01T",
+ "2020-01-01T25:00:00",
+ "2020-01-01T01:60:00",
+ "2020-01-01T01:60:61",
+ "2020-01-01junk",
+ "2020-01-01T00:00:00junk",
+ "2020-01-01T00:00:00+00:00junk",
+ "2020-01-01T00:00:00+00:00[UTC]junk",
+ "2020-01-01T00:00:00+00:00[UTC][u-ca=iso8601]junk",
+ "02020-01-01",
+ "2020-001-01",
+ "2020-01-001",
+ "2020-01-01T001",
+ "2020-01-01T01:001",
+ "2020-01-01T01:01:001",
+ // valid, but forms not supported in Temporal:
+ "2020-W01-1",
+ "2020-001",
+ "+0002020-01-01",
+ // valid, but this calendar must not exist:
+ "2020-01-01[u-ca=notexist]",
+ // may be valid in other contexts, but insufficient information for PlainDate:
+ "2020-01",
+ "+002020-01",
+ "01-01",
+ "2020-W01",
+ "P1Y",
+ "-P12Y",
+ // valid, but outside the supported range:
+ "-999999-01-01",
+ "+999999-01-01",
+];
+const instance = new Temporal.Calendar("iso8601");
+for (const arg of invalidStrings) {
+ assert.throws(
+ RangeError,
+ () => instance.day(arg),
+ `"${arg}" should not be a valid ISO string for a PlainDate`
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-string-multiple-calendar.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-string-multiple-calendar.js
new file mode 100644
index 0000000000..15643ab93c
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-string-multiple-calendar.js
@@ -0,0 +1,32 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.day
+description: >
+ More than one calendar annotation is not syntactical if any have the criical
+ flag
+features: [Temporal]
+---*/
+
+const invalidStrings = [
+ "1970-01-01[u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01[!u-ca=iso8601][u-ca=iso8601]",
+ "1970-01-01[UTC][u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01[u-ca=iso8601][foo=bar][!u-ca=iso8601]",
+ "1970-01-01T00:00[u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01T00:00[!u-ca=iso8601][u-ca=iso8601]",
+ "1970-01-01T00:00[UTC][u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01T00:00[u-ca=iso8601][foo=bar][!u-ca=iso8601]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.day(arg),
+ `reject more than one calendar annotation if any critical: ${arg}`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-string-multiple-time-zone.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-string-multiple-time-zone.js
new file mode 100644
index 0000000000..3d84d9f531
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-string-multiple-time-zone.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.day
+description: More than one time zone annotation is not syntactical
+features: [Temporal]
+---*/
+
+const invalidStrings = [
+ "1970-01-01[UTC][UTC]",
+ "1970-01-01T00:00[UTC][UTC]",
+ "1970-01-01T00:00[!UTC][UTC]",
+ "1970-01-01T00:00[UTC][!UTC]",
+ "1970-01-01T00:00[UTC][u-ca=iso8601][UTC]",
+ "1970-01-01T00:00[UTC][foo=bar][UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.day(arg),
+ `reject more than one time zone annotation: ${arg}`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-string-time-separators.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-string-time-separators.js
new file mode 100644
index 0000000000..4fafb7248b
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-string-time-separators.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.day
+description: Time separator in string argument can vary
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02T15:23", "uppercase T"],
+ ["2000-05-02t15:23", "lowercase T"],
+ ["2000-05-02 15:23", "space between date and time"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.day(arg);
+
+ assert.sameValue(
+ result,
+ 2,
+ `variant time separators (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-string-time-zone-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-string-time-zone-annotation.js
new file mode 100644
index 0000000000..e688ec555f
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-string-time-zone-annotation.js
@@ -0,0 +1,38 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.day
+description: Various forms of time zone annotation; critical flag has no effect
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02[Asia/Kolkata]", "named, with no time"],
+ ["2000-05-02[!Europe/Vienna]", "named, with ! and no time"],
+ ["2000-05-02[+00:00]", "numeric, with no time"],
+ ["2000-05-02[!-02:30]", "numeric, with ! and no time"],
+ ["2000-05-02T15:23[America/Sao_Paulo]", "named, with no offset"],
+ ["2000-05-02T15:23[!Asia/Tokyo]", "named, with ! and no offset"],
+ ["2000-05-02T15:23[-02:30]", "numeric, with no offset"],
+ ["2000-05-02T15:23[!+00:00]", "numeric, with ! and no offset"],
+ ["2000-05-02T15:23+00:00[America/New_York]", "named, with offset"],
+ ["2000-05-02T15:23+00:00[!UTC]", "named, with offset and !"],
+ ["2000-05-02T15:23+00:00[+01:00]", "numeric, with offset"],
+ ["2000-05-02T15:23+00:00[!-08:00]", "numeric, with offset and !"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.day(arg);
+
+ assert.sameValue(
+ result,
+ 2,
+ `time zone annotation (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-string-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-string-unknown-annotation.js
new file mode 100644
index 0000000000..7c98fe71e4
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-string-unknown-annotation.js
@@ -0,0 +1,32 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.day
+description: Various forms of unknown annotation
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02[foo=bar]", "without time"],
+ ["2000-05-02T15:23[foo=bar]", "alone"],
+ ["2000-05-02T15:23[UTC][foo=bar]", "with time zone"],
+ ["2000-05-02T15:23[u-ca=iso8601][foo=bar]", "with calendar"],
+ ["2000-05-02T15:23[UTC][foo=bar][u-ca=iso8601]", "with time zone and calendar"],
+ ["2000-05-02T15:23[foo=bar][_foo-bar0=Ignore-This-999999999999]", "with another unknown annotation"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.day(arg);
+
+ assert.sameValue(
+ result,
+ 2,
+ `unknown annotation (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-string-with-utc-designator.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-string-with-utc-designator.js
new file mode 100644
index 0000000000..b1deda8354
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-string-with-utc-designator.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.day
+description: RangeError thrown if a string with UTC designator is used as a PlainDate
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ "2019-10-01T09:00:00Z",
+ "2019-10-01T09:00:00Z[UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.day(arg),
+ "String with UTC designator should not be valid as a PlainDate"
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-wrong-type.js
new file mode 100644
index 0000000000..8e225e2bcb
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-wrong-type.js
@@ -0,0 +1,43 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.day
+description: >
+ Appropriate error thrown when argument cannot be converted to a valid string
+ or property bag for PlainDate
+features: [BigInt, Symbol, Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const primitiveTests = [
+ [undefined, "undefined"],
+ [null, "null"],
+ [true, "boolean"],
+ ["", "empty string"],
+ [1, "number that doesn't convert to a valid ISO string"],
+ [1n, "bigint"],
+];
+
+for (const [arg, description] of primitiveTests) {
+ assert.throws(
+ typeof arg === 'string' ? RangeError : TypeError,
+ () => instance.day(arg),
+ `${description} does not convert to a valid ISO string`
+ );
+}
+
+const typeErrorTests = [
+ [Symbol(), "symbol"],
+ [{}, "plain object"],
+ [Temporal.PlainDate, "Temporal.PlainDate, object"],
+ [Temporal.PlainDate.prototype, "Temporal.PlainDate.prototype, object"],
+];
+
+for (const [arg, description] of typeErrorTests) {
+ assert.throws(TypeError, () => instance.day(arg), `${description} is not a valid property bag and does not convert to a string`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-zoneddatetime-convert.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-zoneddatetime-convert.js
new file mode 100644
index 0000000000..51bf0e2db4
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-zoneddatetime-convert.js
@@ -0,0 +1,22 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.day
+description: An exception from TimeZone#getOffsetNanosecondsFor() is propagated.
+features: [Temporal]
+---*/
+
+class TZ extends Temporal.TimeZone {
+ constructor() { super("UTC") }
+ getOffsetNanosecondsFor() { throw new Test262Error() }
+}
+
+const tz = new TZ();
+const arg = new Temporal.ZonedDateTime(0n, tz);
+const instance = new Temporal.Calendar("iso8601");
+
+assert.throws(Test262Error, () => instance.day(arg));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-zoneddatetime-slots.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-zoneddatetime-slots.js
new file mode 100644
index 0000000000..87f13d142c
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-zoneddatetime-slots.js
@@ -0,0 +1,40 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.day
+description: Getters are not called when converting a ZonedDateTime to a PlainDate.
+includes: [compareArray.js]
+features: [Temporal]
+---*/
+
+const actual = [];
+const prototypeDescrs = Object.getOwnPropertyDescriptors(Temporal.ZonedDateTime.prototype);
+const getters = ["year", "month", "monthCode", "day", "hour", "minute", "second", "millisecond", "microsecond", "nanosecond", "calendar"];
+
+for (const property of getters) {
+ Object.defineProperty(Temporal.ZonedDateTime.prototype, property, {
+ get() {
+ actual.push(`get ${property}`);
+ const value = prototypeDescrs[property].get.call(this);
+ return {
+ toString() {
+ actual.push(`toString ${property}`);
+ return value.toString();
+ },
+ valueOf() {
+ actual.push(`valueOf ${property}`);
+ return value;
+ },
+ };
+ },
+ });
+}
+
+const arg = new Temporal.ZonedDateTime(0n, "UTC");
+const instance = new Temporal.Calendar("iso8601");
+instance.day(arg);
+assert.compareArray(actual, []);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js
new file mode 100644
index 0000000000..7f3731cfd4
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.day
+description: RangeError thrown if time zone reports an offset that is not an integer number of nanoseconds
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+[3600_000_000_000.5, NaN, -Infinity, Infinity].forEach((wrongOffset) => {
+ const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset);
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ assert.throws(RangeError, () => calendar.day(datetime));
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js
new file mode 100644
index 0000000000..9809d9a0f7
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.day
+description: TypeError thrown if timeZone.getOffsetNanosecondsFor is not callable
+features: [BigInt, Symbol, Temporal, arrow-function]
+---*/
+
+[undefined, null, true, Math.PI, 'string', Symbol('sym'), 42n, {}].forEach((notCallable) => {
+ const timeZone = new Temporal.TimeZone("UTC");
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ timeZone.getOffsetNanosecondsFor = notCallable;
+ assert.throws(
+ TypeError,
+ () => calendar.day(datetime),
+ `Uncallable ${notCallable === null ? 'null' : typeof notCallable} getOffsetNanosecondsFor should throw TypeError`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js
new file mode 100644
index 0000000000..71d7ae998a
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.day
+description: RangeError thrown if time zone reports an offset that is out of range
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+[-86400_000_000_000, 86400_000_000_000].forEach((wrongOffset) => {
+ const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset);
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ assert.throws(RangeError, () => calendar.day(datetime));
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js
new file mode 100644
index 0000000000..d9964911f5
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.day
+description: TypeError thrown if time zone reports an offset that is not a Number
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+[
+ undefined,
+ null,
+ true,
+ "+01:00",
+ Symbol(),
+ 3600_000_000_000n,
+ {},
+ { valueOf() { return 3600_000_000_000; } },
+].forEach((wrongOffset) => {
+ const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset);
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ assert.throws(TypeError, () => calendar.day(datetime));
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/basic.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/basic.js
new file mode 100644
index 0000000000..710f903710
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/basic.js
@@ -0,0 +1,20 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.day
+description: Basic tests for day().
+features: [Temporal]
+---*/
+
+const iso = Temporal.Calendar.from("iso8601");
+const res = 5;
+assert.sameValue(iso.day(Temporal.PlainDate.from("1994-11-05")), res, "PlainDate");
+assert.sameValue(iso.day(Temporal.PlainDateTime.from("1994-11-05T08:15:30")), res, "PlainDateTime");
+assert.sameValue(iso.day(Temporal.PlainMonthDay.from("11-05")), res, "PlainMonthDay");
+assert.sameValue(iso.day({ year: 1994, month: 11, day: 5 }), res, "property bag");
+assert.sameValue(iso.day("1994-11-05"), res, "string");
+assert.throws(TypeError, () => iso.day({ year: 2000 }), "property bag with missing properties");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/branding.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/branding.js
new file mode 100644
index 0000000000..b77d8a8109
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/branding.js
@@ -0,0 +1,27 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.day
+description: Throw a TypeError if the receiver is invalid
+features: [Symbol, Temporal]
+---*/
+
+const day = Temporal.Calendar.prototype.day;
+
+assert.sameValue(typeof day, "function");
+
+const args = [new Temporal.PlainDate(2000, 1, 1)];
+
+assert.throws(TypeError, () => day.apply(undefined, args), "undefined");
+assert.throws(TypeError, () => day.apply(null, args), "null");
+assert.throws(TypeError, () => day.apply(true, args), "true");
+assert.throws(TypeError, () => day.apply("", args), "empty string");
+assert.throws(TypeError, () => day.apply(Symbol(), args), "symbol");
+assert.throws(TypeError, () => day.apply(1, args), "1");
+assert.throws(TypeError, () => day.apply({}, args), "plain object");
+assert.throws(TypeError, () => day.apply(Temporal.Calendar, args), "Temporal.Calendar");
+assert.throws(TypeError, () => day.apply(Temporal.Calendar.prototype, args), "Temporal.Calendar.prototype");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/browser.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/browser.js
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/builtin.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/builtin.js
new file mode 100644
index 0000000000..5930579457
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/builtin.js
@@ -0,0 +1,36 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.day
+description: >
+ Tests that Temporal.Calendar.prototype.day
+ meets the requirements for built-in objects defined by the
+ introduction of chapter 17 of the ECMAScript Language Specification.
+info: |
+ Built-in functions that are not constructors do not have a "prototype" property unless
+ otherwise specified in the description of a particular function.
+
+ Unless specified otherwise, a built-in object that is callable as a function is a built-in
+ function object with the characteristics described in 10.3. Unless specified otherwise, the
+ [[Extensible]] internal slot of a built-in object initially has the value true.
+
+ Unless otherwise specified every built-in function and every built-in constructor has the
+ Function prototype object [...] as the value of its [[Prototype]] internal slot.
+features: [Temporal]
+---*/
+
+assert.sameValue(Object.isExtensible(Temporal.Calendar.prototype.day),
+ true, "Built-in objects must be extensible.");
+
+assert.sameValue(Object.prototype.toString.call(Temporal.Calendar.prototype.day),
+ "[object Function]", "Object.prototype.toString");
+
+assert.sameValue(Object.getPrototypeOf(Temporal.Calendar.prototype.day),
+ Function.prototype, "prototype");
+
+assert.sameValue(Temporal.Calendar.prototype.day.hasOwnProperty("prototype"),
+ false, "prototype property");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/calendar-datefromfields-called-with-options-undefined.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/calendar-datefromfields-called-with-options-undefined.js
new file mode 100644
index 0000000000..46b9873fc8
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/calendar-datefromfields-called-with-options-undefined.js
@@ -0,0 +1,18 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.day
+description: >
+ Calendar.dateFromFields method is called with undefined as the options value
+ when call originates internally
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions();
+calendar.day({ year: 2000, month: 5, day: 3, calendar });
+assert.sameValue(calendar.dateFromFieldsCallCount, 1);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/calendar-fields-iterable.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/calendar-fields-iterable.js
new file mode 100644
index 0000000000..4410ec4006
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/calendar-fields-iterable.js
@@ -0,0 +1,37 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.day
+description: Verify the result of calendar.fields() is treated correctly.
+info: |
+ sec-temporal.calendar.prototype.day step 4:
+ 4. Return ? ISODay(_dateOrDateTime_).
+ sec-temporal-isoday step 1.a:
+ a. Set _dateOrDateTime_ to ? ToTemporalDate(_dateOrDateTime_).
+ sec-temporal-totemporaldate step 2.c:
+ c. Let _fieldNames_ be ? CalendarFields(calendar, « *"day"*, *"month"*, *"monthCode"*, *"year"* »).
+ sec-temporal-calendarfields step 4:
+ 4. Let _result_ be ? IterableToListOfType(_fieldsArray_, « String »).
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const expected = [
+ "day",
+ "month",
+ "monthCode",
+ "year",
+];
+
+const calendar1 = TemporalHelpers.calendarFieldsIterable();
+const calendar2 = TemporalHelpers.calendarFieldsIterable();
+calendar1.day({ year: 2000, month: 5, day: 2, calendar: calendar2 });
+
+assert.sameValue(calendar1.fieldsCallCount, 0, "fields() method not called");
+assert.sameValue(calendar2.fieldsCallCount, 1, "fields() method called once");
+assert.compareArray(calendar2.fieldsCalledWith[0], expected, "fields() method called with correct args");
+assert(calendar2.iteratorExhausted[0], "iterated through the whole iterable");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/calendar-temporal-object.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/calendar-temporal-object.js
new file mode 100644
index 0000000000..b40cc5dcd5
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/calendar-temporal-object.js
@@ -0,0 +1,31 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.day
+description: Fast path for converting other Temporal objects to Temporal.Calendar by reading internal slots
+info: |
+ sec-temporal.calendar.prototype.day step 4:
+ 4. Return ? ISODay(_dateOrDateTime_).
+ sec-temporal-isoday step 1.a:
+ a. Set _dateOrDateTime_ to ? ToTemporalDate(_dateOrDateTime_).
+ sec-temporal-totemporaldate step 2.c:
+ c. Let _calendar_ be ? GetTemporalCalendarWithISODefault(_item_).
+ sec-temporal-gettemporalcalendarwithisodefault step 2:
+ 2. Return ? ToTemporalCalendarWithISODefault(_calendar_).
+ sec-temporal-totemporalcalendarwithisodefault step 2:
+ 3. Return ? ToTemporalCalendar(_temporalCalendarLike_).
+ sec-temporal-totemporalcalendar step 1.a:
+ a. If _temporalCalendarLike_ has an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]], [[InitializedTemporalMonthDay]], [[InitializedTemporalYearMonth]], or [[InitializedTemporalZonedDateTime]] internal slot, then
+ i. Return _temporalCalendarLike_.[[Calendar]].
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+TemporalHelpers.checkToTemporalCalendarFastPath((temporalObject) => {
+ const calendar = new Temporal.Calendar("iso8601");
+ calendar.day({ year: 2000, month: 5, day: 2, calendar: temporalObject });
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/date-time.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/date-time.js
new file mode 100644
index 0000000000..d664a65afa
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/date-time.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.day
+description: >
+ Temporal.Calendar.prototype.day will take PlainDateTime and return
+ the value of the day.
+info: |
+ 5. Return ! ISODay(temporalDateLike).
+features: [Temporal]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+let dateTime = new Temporal.PlainDateTime(1997, 8, 23, 5, 30, 13)
+assert.sameValue(cal.day(dateTime), 23, 'cal.day(new Temporal.PlainDateTime(1997, 8, 23, 5, 30, 13)) must return 23');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/date.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/date.js
new file mode 100644
index 0000000000..e78ca47b51
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/date.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.day
+description: >
+ Temporal.Calendar.prototype.day will take PlainDate and return
+ the value of the day.
+info: |
+ 5. Return ! ISODay(temporalDateLike).
+features: [Temporal]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+let date = new Temporal.PlainDate(2021, 7, 15);
+assert.sameValue(cal.day(date), 15, 'cal.day(new Temporal.PlainDate(2021, 7, 15)) must return 15');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/infinity-throws-rangeerror.js
new file mode 100644
index 0000000000..0488591f63
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/infinity-throws-rangeerror.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: Throws if any value in the property bag is Infinity or -Infinity
+esid: sec-temporal.calendar.prototype.day
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+const base = { year: 2000, month: 5, day: 2 };
+
+[Infinity, -Infinity].forEach((inf) => {
+ ["year", "month", "day"].forEach((prop) => {
+ assert.throws(RangeError, () => instance.day({ ...base, [prop]: inf }), `${prop} property cannot be ${inf}`);
+
+ const calls = [];
+ const obj = TemporalHelpers.toPrimitiveObserver(calls, inf, prop);
+ assert.throws(RangeError, () => instance.day({ ...base, [prop]: obj }));
+ assert.compareArray(calls, [`get ${prop}.valueOf`, `call ${prop}.valueOf`], "it fails after fetching the primitive value");
+ });
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/length.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/length.js
new file mode 100644
index 0000000000..009a8695f2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/length.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2020 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.day
+description: Temporal.Calendar.prototype.day.length is 1
+info: |
+ Every built-in function object, including constructors, has a "length" property whose value is
+ an integer. Unless otherwise specified, this value is equal to the largest number of named
+ arguments shown in the subclause headings for the function description. Optional parameters
+ (which are indicated with brackets: [ ]) or rest parameters (which are shown using the form
+ «...name») are not included in the default argument count.
+
+ Unless otherwise specified, the "length" property of a built-in function object has the
+ attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+verifyProperty(Temporal.Calendar.prototype.day, "length", {
+ value: 1,
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/month-day.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/month-day.js
new file mode 100644
index 0000000000..b0f989774f
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/month-day.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.day
+description: >
+ Temporal.Calendar.prototype.day will take PlainMonthDay and return
+ the value of the day.
+info: |
+ 4. If Type(temporalDateLike) is not Object or temporalDateLike does not have
+ an [[InitializedTemporalDate]] or [[InitializedTemporalYearMonth]] internal
+ slot, then
+ a. Set temporalDateLike to ? ToTemporalDate(temporalDateLike).
+ 5. Return ! ISODay(temporalDateLike).
+features: [Temporal]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+let monthDay = new Temporal.PlainMonthDay(7, 15);
+assert.sameValue(cal.day(monthDay), 15, 'cal.day(new Temporal.PlainMonthDay(7, 15)) must return 15');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/name.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/name.js
new file mode 100644
index 0000000000..81ecf1d75b
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/name.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.day
+description: Temporal.Calendar.prototype.day.name is "day".
+info: |
+ Every built-in function object, including constructors, that is not identified as an anonymous
+ function has a "name" property whose value is a String. Unless otherwise specified, this value
+ is the name that is given to the function in this specification.
+
+ Unless otherwise specified, the "name" property of a built-in function object, if it exists,
+ has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+verifyProperty(Temporal.Calendar.prototype.day, "name", {
+ value: "day",
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/not-a-constructor.js
new file mode 100644
index 0000000000..b754eb84c0
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/not-a-constructor.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.day
+description: >
+ Temporal.Calendar.prototype.day does not implement [[Construct]], is not new-able
+info: |
+ Built-in function objects that are not identified as constructors do not implement the
+ [[Construct]] internal method unless otherwise specified in the description of a particular
+ function.
+includes: [isConstructor.js]
+features: [Reflect.construct, Temporal]
+---*/
+
+assert.throws(TypeError, () => {
+ new Temporal.Calendar.prototype.day();
+}, "Calling as constructor");
+
+assert.sameValue(isConstructor(Temporal.Calendar.prototype.day), false,
+ "isConstructor(Temporal.Calendar.prototype.day)");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/prop-desc.js
new file mode 100644
index 0000000000..868d426d89
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/prop-desc.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.day
+description: The "day" property of Temporal.Calendar.prototype
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+assert.sameValue(
+ typeof Temporal.Calendar.prototype.day,
+ "function",
+ "`typeof Calendar.prototype.day` is `function`"
+);
+
+verifyProperty(Temporal.Calendar.prototype, "day", {
+ writable: true,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/shell.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/shell.js
new file mode 100644
index 0000000000..eda1477282
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/shell.js
@@ -0,0 +1,24 @@
+// GENERATED, DO NOT EDIT
+// file: isConstructor.js
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: |
+ Test if a given function is a constructor function.
+defines: [isConstructor]
+features: [Reflect.construct]
+---*/
+
+function isConstructor(f) {
+ if (typeof f !== "function") {
+ throw new Test262Error("isConstructor invoked with a non-function value");
+ }
+
+ try {
+ Reflect.construct(function(){}, [], f);
+ } catch (e) {
+ return false;
+ }
+ return true;
+}
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/string.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/string.js
new file mode 100644
index 0000000000..9128672148
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/string.js
@@ -0,0 +1,22 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.day
+description: >
+ Temporal.Calendar.prototype.day will take ISO8601 string and return
+ the value of the day.
+info: |
+ 4. If Type(temporalDateLike) is not Object or temporalDateLike does not have
+ an [[InitializedTemporalDate]] or [[InitializedTemporalYearMonth]] internal
+ slot, then
+ a. Set temporalDateLike to ? ToTemporalDate(temporalDateLike).
+ 5. Return ! ISODay(temporalDateLike).
+features: [Temporal]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+assert.sameValue(cal.day("2019-03-15"), 15, 'cal.day("2019-03-15") must return 15');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/throw-range-error-ToTemporalDate.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/throw-range-error-ToTemporalDate.js
new file mode 100644
index 0000000000..1ea947ca9e
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/throw-range-error-ToTemporalDate.js
@@ -0,0 +1,22 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.day
+description: >
+ Temporal.Calendar.prototype.day throws RangeError on
+ ToTemporalDate when temporalDateLike is invalid string.
+info: |
+ 4. If Type(temporalDateLike) is not Object or temporalDateLike
+ does not have an [[InitializedTemporalDate]] or
+ [[InitializedTemporalYearMonth]] internal slot, then
+ a. Set temporalDateLike to ? ToTemporalDate(temporalDateLike).
+features: [Temporal, arrow-function]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+assert.throws(RangeError, () => cal.day("invalid string"),
+ 'cal.day("invalid string") throws a RangeError exception');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/year-zero.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/year-zero.js
new file mode 100644
index 0000000000..f1c0e19e8c
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/day/year-zero.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.day
+description: Negative zero, as an extended year, is rejected
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ "-000000-10-31",
+ "-000000-10-31T00:45",
+ "-000000-10-31T00:45+01:00",
+ "-000000-10-31T00:45+00:00[UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.day(arg),
+ "reject minus zero as extended year"
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-builtin-calendar-no-array-iteration.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-builtin-calendar-no-array-iteration.js
new file mode 100644
index 0000000000..099a7b859b
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-builtin-calendar-no-array-iteration.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofweek
+description: >
+ Calling the method with a property bag argument with a builtin calendar causes
+ no observable array iteration when getting the calendar fields.
+features: [Temporal]
+---*/
+
+const arrayPrototypeSymbolIteratorOriginal = Array.prototype[Symbol.iterator];
+Array.prototype[Symbol.iterator] = function arrayIterator() {
+ throw new Test262Error("Array should not be iterated");
+}
+
+const instance = new Temporal.Calendar("iso8601");
+const arg = { year: 2000, month: 5, day: 2, calendar: "iso8601" };
+instance.dayOfWeek(arg);
+
+Array.prototype[Symbol.iterator] = arrayPrototypeSymbolIteratorOriginal;
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-calendar-datefromfields-called-with-null-prototype-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-calendar-datefromfields-called-with-null-prototype-fields.js
new file mode 100644
index 0000000000..00120c596a
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-calendar-datefromfields-called-with-null-prototype-fields.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofweek
+description: >
+ Calendar.dateFromFields method is called with a null-prototype fields object
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarCheckFieldsPrototypePollution();
+const instance = new Temporal.Calendar("iso8601");
+const arg = { year: 2000, month: 5, day: 2, calendar };
+instance.dayOfWeek(arg);
+assert.sameValue(calendar.dateFromFieldsCallCount, 1, "dateFromFields should be called on the property bag's calendar");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-constructor-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-constructor-in-calendar-fields.js
new file mode 100644
index 0000000000..7839fb6454
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-constructor-in-calendar-fields.js
@@ -0,0 +1,17 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.dayofweek
+description: If a calendar's fields() method returns a field named 'constructor', PrepareTemporalFields should throw a RangeError.
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarWithExtraFields(['constructor']);
+const arg = {year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar};
+const instance = new Temporal.Calendar("iso8601");
+
+assert.throws(RangeError, () => instance.dayOfWeek(arg));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-duplicate-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-duplicate-calendar-fields.js
new file mode 100644
index 0000000000..d492982e7f
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-duplicate-calendar-fields.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.dayofweek
+description: If a calendar's fields() method returns duplicate field names, PrepareTemporalFields should throw a RangeError.
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+for (const extra_fields of [['foo', 'foo'], ['day'], ['month'], ['monthCode'], ['year']]) {
+ const calendar = TemporalHelpers.calendarWithExtraFields(extra_fields);
+ const arg = { year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar };
+ const instance = new Temporal.Calendar("iso8601");
+
+ assert.throws(RangeError, () => instance.dayOfWeek(arg));
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-leap-second.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-leap-second.js
new file mode 100644
index 0000000000..5f528093ba
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-leap-second.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofweek
+description: Leap second is a valid ISO string for PlainDate
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+let arg = "2016-12-31T23:59:60";
+const result1 = instance.dayOfWeek(arg);
+assert.sameValue(
+ result1,
+ 6,
+ "leap second is a valid ISO string for PlainDate"
+);
+
+arg = { year: 2016, month: 12, day: 31, hour: 23, minute: 59, second: 60 };
+const result2 = instance.dayOfWeek(arg);
+assert.sameValue(
+ result2,
+ 6,
+ "second: 60 is ignored in property bag for PlainDate"
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-number.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-number.js
new file mode 100644
index 0000000000..6aa86300b1
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-number.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofweek
+description: A number cannot be used in place of a Temporal.PlainDate
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const numbers = [
+ 1,
+ 19761118,
+ -19761118,
+ 1234567890,
+];
+
+for (const arg of numbers) {
+ assert.throws(
+ TypeError,
+ () => instance.dayOfWeek(arg),
+ 'Numbers cannot be used in place of an ISO string for PlainDate'
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-propertybag-calendar-case-insensitive.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-propertybag-calendar-case-insensitive.js
new file mode 100644
index 0000000000..afa01ac2f3
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-propertybag-calendar-case-insensitive.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofweek
+description: The calendar name is case-insensitive
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const calendar = "IsO8601";
+
+const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+const result = instance.dayOfWeek(arg);
+assert.sameValue(result, 4, "Calendar is case-insensitive");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-propertybag-calendar-leap-second.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-propertybag-calendar-leap-second.js
new file mode 100644
index 0000000000..014649fad0
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-propertybag-calendar-leap-second.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofweek
+description: Leap second is a valid ISO string for a calendar in a property bag
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const calendar = "2016-12-31T23:59:60";
+
+const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+const result = instance.dayOfWeek(arg);
+assert.sameValue(
+ result,
+ 4,
+ "leap second is a valid ISO string for calendar"
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-propertybag-calendar-number.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-propertybag-calendar-number.js
new file mode 100644
index 0000000000..8a041042d2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-propertybag-calendar-number.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofweek
+description: A number as calendar in a property bag is not accepted
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const numbers = [
+ 1,
+ 19970327,
+ -19970327,
+ 1234567890,
+];
+
+for (const calendar of numbers) {
+ const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+ assert.throws(
+ TypeError,
+ () => instance.dayOfWeek(arg),
+ "Numbers cannot be used as a calendar"
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-propertybag-calendar-string.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-propertybag-calendar-string.js
new file mode 100644
index 0000000000..64a59dcc51
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-propertybag-calendar-string.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofweek
+description: A calendar ID is valid input for Calendar
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const calendar = "iso8601";
+
+const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+const result = instance.dayOfWeek(arg);
+assert.sameValue(result, 4, `Calendar created from string "${calendar}"`);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-propertybag-calendar-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-propertybag-calendar-wrong-type.js
new file mode 100644
index 0000000000..ffd6082e3b
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-propertybag-calendar-wrong-type.js
@@ -0,0 +1,46 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofweek
+description: >
+ Appropriate error thrown when a calendar property from a property bag cannot
+ be converted to a calendar object or string
+features: [BigInt, Symbol, Temporal]
+---*/
+
+const timeZone = new Temporal.TimeZone("UTC");
+const instance = new Temporal.Calendar("iso8601");
+
+const primitiveTests = [
+ [null, "null"],
+ [true, "boolean"],
+ ["", "empty string"],
+ [1, "number that doesn't convert to a valid ISO string"],
+ [1n, "bigint"],
+];
+
+for (const [calendar, description] of primitiveTests) {
+ const arg = { year: 2019, monthCode: "M11", day: 1, calendar };
+ assert.throws(
+ typeof calendar === 'string' ? RangeError : TypeError,
+ () => instance.dayOfWeek(arg),
+ `${description} does not convert to a valid ISO string`
+ );
+}
+
+const typeErrorTests = [
+ [Symbol(), "symbol"],
+ [{}, "plain object that doesn't implement the protocol"],
+ [new Temporal.TimeZone("UTC"), "time zone instance"],
+ [Temporal.Calendar, "Temporal.Calendar, object"],
+ [Temporal.Calendar.prototype, "Temporal.Calendar.prototype, object"], // fails brand check in dateFromFields()
+];
+
+for (const [calendar, description] of typeErrorTests) {
+ const arg = { year: 2019, monthCode: "M11", day: 1, calendar };
+ assert.throws(TypeError, () => instance.dayOfWeek(arg), `${description} is not a valid property bag and does not convert to a string`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-propertybag-calendar-year-zero.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-propertybag-calendar-year-zero.js
new file mode 100644
index 0000000000..767b87d15d
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-propertybag-calendar-year-zero.js
@@ -0,0 +1,27 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofweek
+description: Negative zero, as an extended year, is rejected
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ "-000000-10-31",
+ "-000000-10-31T17:45",
+ "-000000-10-31T17:45Z",
+ "-000000-10-31T17:45+01:00",
+ "-000000-10-31T17:45+00:00[UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.dayOfWeek(arg),
+ "reject minus zero as extended year"
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-proto-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-proto-in-calendar-fields.js
new file mode 100644
index 0000000000..efcd36bb13
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-proto-in-calendar-fields.js
@@ -0,0 +1,17 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.dayofweek
+description: If a calendar's fields() method returns a field named '__proto__', PrepareTemporalFields should throw a RangeError.
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarWithExtraFields(['__proto__']);
+const arg = {year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar};
+const instance = new Temporal.Calendar("iso8601");
+
+assert.throws(RangeError, () => instance.dayOfWeek(arg));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-string-calendar-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-string-calendar-annotation.js
new file mode 100644
index 0000000000..06f5075832
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-string-calendar-annotation.js
@@ -0,0 +1,33 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofweek
+description: Various forms of calendar annotation; critical flag has no effect
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02[u-ca=iso8601]", "without time or time zone"],
+ ["2000-05-02[UTC][u-ca=iso8601]", "with time zone and no time"],
+ ["2000-05-02T15:23[u-ca=iso8601]", "without time zone"],
+ ["2000-05-02T15:23[UTC][u-ca=iso8601]", "with time zone"],
+ ["2000-05-02T15:23[!u-ca=iso8601]", "with ! and no time zone"],
+ ["2000-05-02T15:23[UTC][!u-ca=iso8601]", "with ! and time zone"],
+ ["2000-05-02T15:23[u-ca=iso8601][u-ca=discord]", "second annotation ignored"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.dayOfWeek(arg);
+
+ assert.sameValue(
+ result,
+ 2,
+ `calendar annotation (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-string-critical-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-string-critical-unknown-annotation.js
new file mode 100644
index 0000000000..68aed5c169
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-string-critical-unknown-annotation.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofweek
+description: Unknown annotations with critical flag are rejected
+features: [Temporal]
+---*/
+
+const invalidStrings = [
+ "1970-01-01[!foo=bar]",
+ "1970-01-01T00:00[!foo=bar]",
+ "1970-01-01T00:00[UTC][!foo=bar]",
+ "1970-01-01T00:00[u-ca=iso8601][!foo=bar]",
+ "1970-01-01T00:00[UTC][!foo=bar][u-ca=iso8601]",
+ "1970-01-01T00:00[foo=bar][!_foo-bar0=Dont-Ignore-This-99999999999]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.dayOfWeek(arg),
+ `reject unknown annotation with critical flag: ${arg}`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-string-date-with-utc-offset.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-string-date-with-utc-offset.js
new file mode 100644
index 0000000000..bad099d0d8
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-string-date-with-utc-offset.js
@@ -0,0 +1,48 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofweek
+description: UTC offset not valid with format that does not include a time
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const validStrings = [
+ "2000-05-02T00+00:00",
+ "2000-05-02T00+00:00[UTC]",
+ "2000-05-02T00+00:00[!UTC]",
+ "2000-05-02T00-02:30[America/St_Johns]",
+];
+
+for (const arg of validStrings) {
+ const result = instance.dayOfWeek(arg);
+
+ assert.sameValue(
+ result,
+ 2,
+ `"${arg}" is a valid UTC offset with time for PlainDate`
+ );
+}
+
+const invalidStrings = [
+ "2022-09-15Z",
+ "2022-09-15Z[UTC]",
+ "2022-09-15Z[Europe/Vienna]",
+ "2022-09-15+00:00",
+ "2022-09-15+00:00[UTC]",
+ "2022-09-15-02:30",
+ "2022-09-15-02:30[America/St_Johns]",
+];
+
+for (const arg of invalidStrings) {
+ assert.throws(
+ RangeError,
+ () => instance.dayOfWeek(arg),
+ `"${arg}" UTC offset without time is not valid for PlainDate`
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-string-invalid.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-string-invalid.js
new file mode 100644
index 0000000000..ce96c32afe
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-string-invalid.js
@@ -0,0 +1,64 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofweek
+description: >
+ RangeError thrown if an invalid ISO string (or syntactically valid ISO string
+ that is not supported) is used as a PlainDate
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ // invalid ISO strings:
+ "",
+ "invalid iso8601",
+ "2020-01-00",
+ "2020-01-32",
+ "2020-02-30",
+ "2021-02-29",
+ "2020-00-01",
+ "2020-13-01",
+ "2020-01-01T",
+ "2020-01-01T25:00:00",
+ "2020-01-01T01:60:00",
+ "2020-01-01T01:60:61",
+ "2020-01-01junk",
+ "2020-01-01T00:00:00junk",
+ "2020-01-01T00:00:00+00:00junk",
+ "2020-01-01T00:00:00+00:00[UTC]junk",
+ "2020-01-01T00:00:00+00:00[UTC][u-ca=iso8601]junk",
+ "02020-01-01",
+ "2020-001-01",
+ "2020-01-001",
+ "2020-01-01T001",
+ "2020-01-01T01:001",
+ "2020-01-01T01:01:001",
+ // valid, but forms not supported in Temporal:
+ "2020-W01-1",
+ "2020-001",
+ "+0002020-01-01",
+ // valid, but this calendar must not exist:
+ "2020-01-01[u-ca=notexist]",
+ // may be valid in other contexts, but insufficient information for PlainDate:
+ "2020-01",
+ "+002020-01",
+ "01-01",
+ "2020-W01",
+ "P1Y",
+ "-P12Y",
+ // valid, but outside the supported range:
+ "-999999-01-01",
+ "+999999-01-01",
+];
+const instance = new Temporal.Calendar("iso8601");
+for (const arg of invalidStrings) {
+ assert.throws(
+ RangeError,
+ () => instance.dayOfWeek(arg),
+ `"${arg}" should not be a valid ISO string for a PlainDate`
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-string-multiple-calendar.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-string-multiple-calendar.js
new file mode 100644
index 0000000000..0ac61801ab
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-string-multiple-calendar.js
@@ -0,0 +1,32 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofweek
+description: >
+ More than one calendar annotation is not syntactical if any have the criical
+ flag
+features: [Temporal]
+---*/
+
+const invalidStrings = [
+ "1970-01-01[u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01[!u-ca=iso8601][u-ca=iso8601]",
+ "1970-01-01[UTC][u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01[u-ca=iso8601][foo=bar][!u-ca=iso8601]",
+ "1970-01-01T00:00[u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01T00:00[!u-ca=iso8601][u-ca=iso8601]",
+ "1970-01-01T00:00[UTC][u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01T00:00[u-ca=iso8601][foo=bar][!u-ca=iso8601]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.dayOfWeek(arg),
+ `reject more than one calendar annotation if any critical: ${arg}`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-string-multiple-time-zone.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-string-multiple-time-zone.js
new file mode 100644
index 0000000000..c1c244ac4b
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-string-multiple-time-zone.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofweek
+description: More than one time zone annotation is not syntactical
+features: [Temporal]
+---*/
+
+const invalidStrings = [
+ "1970-01-01[UTC][UTC]",
+ "1970-01-01T00:00[UTC][UTC]",
+ "1970-01-01T00:00[!UTC][UTC]",
+ "1970-01-01T00:00[UTC][!UTC]",
+ "1970-01-01T00:00[UTC][u-ca=iso8601][UTC]",
+ "1970-01-01T00:00[UTC][foo=bar][UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.dayOfWeek(arg),
+ `reject more than one time zone annotation: ${arg}`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-string-time-separators.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-string-time-separators.js
new file mode 100644
index 0000000000..e53336a8d8
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-string-time-separators.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofweek
+description: Time separator in string argument can vary
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02T15:23", "uppercase T"],
+ ["2000-05-02t15:23", "lowercase T"],
+ ["2000-05-02 15:23", "space between date and time"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.dayOfWeek(arg);
+
+ assert.sameValue(
+ result,
+ 2,
+ `variant time separators (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-string-time-zone-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-string-time-zone-annotation.js
new file mode 100644
index 0000000000..c802250c95
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-string-time-zone-annotation.js
@@ -0,0 +1,38 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofweek
+description: Various forms of time zone annotation; critical flag has no effect
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02[Asia/Kolkata]", "named, with no time"],
+ ["2000-05-02[!Europe/Vienna]", "named, with ! and no time"],
+ ["2000-05-02[+00:00]", "numeric, with no time"],
+ ["2000-05-02[!-02:30]", "numeric, with ! and no time"],
+ ["2000-05-02T15:23[America/Sao_Paulo]", "named, with no offset"],
+ ["2000-05-02T15:23[!Asia/Tokyo]", "named, with ! and no offset"],
+ ["2000-05-02T15:23[-02:30]", "numeric, with no offset"],
+ ["2000-05-02T15:23[!+00:00]", "numeric, with ! and no offset"],
+ ["2000-05-02T15:23+00:00[America/New_York]", "named, with offset"],
+ ["2000-05-02T15:23+00:00[!UTC]", "named, with offset and !"],
+ ["2000-05-02T15:23+00:00[+01:00]", "numeric, with offset"],
+ ["2000-05-02T15:23+00:00[!-08:00]", "numeric, with offset and !"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.dayOfWeek(arg);
+
+ assert.sameValue(
+ result,
+ 2,
+ `time zone annotation (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-string-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-string-unknown-annotation.js
new file mode 100644
index 0000000000..e7a079cbc0
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-string-unknown-annotation.js
@@ -0,0 +1,32 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofweek
+description: Various forms of unknown annotation
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02[foo=bar]", "without time"],
+ ["2000-05-02T15:23[foo=bar]", "alone"],
+ ["2000-05-02T15:23[UTC][foo=bar]", "with time zone"],
+ ["2000-05-02T15:23[u-ca=iso8601][foo=bar]", "with calendar"],
+ ["2000-05-02T15:23[UTC][foo=bar][u-ca=iso8601]", "with time zone and calendar"],
+ ["2000-05-02T15:23[foo=bar][_foo-bar0=Ignore-This-999999999999]", "with another unknown annotation"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.dayOfWeek(arg);
+
+ assert.sameValue(
+ result,
+ 2,
+ `unknown annotation (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-string-with-utc-designator.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-string-with-utc-designator.js
new file mode 100644
index 0000000000..3a08fea3c6
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-string-with-utc-designator.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofweek
+description: RangeError thrown if a string with UTC designator is used as a PlainDate
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ "2019-10-01T09:00:00Z",
+ "2019-10-01T09:00:00Z[UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.dayOfWeek(arg),
+ "String with UTC designator should not be valid as a PlainDate"
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-wrong-type.js
new file mode 100644
index 0000000000..a1fdcb177e
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-wrong-type.js
@@ -0,0 +1,43 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofweek
+description: >
+ Appropriate error thrown when argument cannot be converted to a valid string
+ or property bag for PlainDate
+features: [BigInt, Symbol, Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const primitiveTests = [
+ [undefined, "undefined"],
+ [null, "null"],
+ [true, "boolean"],
+ ["", "empty string"],
+ [1, "number that doesn't convert to a valid ISO string"],
+ [1n, "bigint"],
+];
+
+for (const [arg, description] of primitiveTests) {
+ assert.throws(
+ typeof arg === 'string' ? RangeError : TypeError,
+ () => instance.dayOfWeek(arg),
+ `${description} does not convert to a valid ISO string`
+ );
+}
+
+const typeErrorTests = [
+ [Symbol(), "symbol"],
+ [{}, "plain object"],
+ [Temporal.PlainDate, "Temporal.PlainDate, object"],
+ [Temporal.PlainDate.prototype, "Temporal.PlainDate.prototype, object"],
+];
+
+for (const [arg, description] of typeErrorTests) {
+ assert.throws(TypeError, () => instance.dayOfWeek(arg), `${description} is not a valid property bag and does not convert to a string`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-zoneddatetime-convert.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-zoneddatetime-convert.js
new file mode 100644
index 0000000000..9b65728bd8
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-zoneddatetime-convert.js
@@ -0,0 +1,22 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofweek
+description: An exception from TimeZone#getOffsetNanosecondsFor() is propagated.
+features: [Temporal]
+---*/
+
+class TZ extends Temporal.TimeZone {
+ constructor() { super("UTC") }
+ getOffsetNanosecondsFor() { throw new Test262Error() }
+}
+
+const tz = new TZ();
+const arg = new Temporal.ZonedDateTime(0n, tz);
+const instance = new Temporal.Calendar("iso8601");
+
+assert.throws(Test262Error, () => instance.dayOfWeek(arg));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-zoneddatetime-slots.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-zoneddatetime-slots.js
new file mode 100644
index 0000000000..e73205db91
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-zoneddatetime-slots.js
@@ -0,0 +1,40 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofweek
+description: Getters are not called when converting a ZonedDateTime to a PlainDate.
+includes: [compareArray.js]
+features: [Temporal]
+---*/
+
+const actual = [];
+const prototypeDescrs = Object.getOwnPropertyDescriptors(Temporal.ZonedDateTime.prototype);
+const getters = ["year", "month", "monthCode", "day", "hour", "minute", "second", "millisecond", "microsecond", "nanosecond", "calendar"];
+
+for (const property of getters) {
+ Object.defineProperty(Temporal.ZonedDateTime.prototype, property, {
+ get() {
+ actual.push(`get ${property}`);
+ const value = prototypeDescrs[property].get.call(this);
+ return {
+ toString() {
+ actual.push(`toString ${property}`);
+ return value.toString();
+ },
+ valueOf() {
+ actual.push(`valueOf ${property}`);
+ return value;
+ },
+ };
+ },
+ });
+}
+
+const arg = new Temporal.ZonedDateTime(0n, "UTC");
+const instance = new Temporal.Calendar("iso8601");
+instance.dayOfWeek(arg);
+assert.compareArray(actual, []);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js
new file mode 100644
index 0000000000..fd111b05c3
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofweek
+description: RangeError thrown if time zone reports an offset that is not an integer number of nanoseconds
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+[3600_000_000_000.5, NaN, -Infinity, Infinity].forEach((wrongOffset) => {
+ const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset);
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ assert.throws(RangeError, () => calendar.dayOfWeek(datetime));
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js
new file mode 100644
index 0000000000..83f279131c
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofweek
+description: TypeError thrown if timeZone.getOffsetNanosecondsFor is not callable
+features: [BigInt, Symbol, Temporal, arrow-function]
+---*/
+
+[undefined, null, true, Math.PI, 'string', Symbol('sym'), 42n, {}].forEach((notCallable) => {
+ const timeZone = new Temporal.TimeZone("UTC");
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ timeZone.getOffsetNanosecondsFor = notCallable;
+ assert.throws(
+ TypeError,
+ () => calendar.dayOfWeek(datetime),
+ `Uncallable ${notCallable === null ? 'null' : typeof notCallable} getOffsetNanosecondsFor should throw TypeError`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js
new file mode 100644
index 0000000000..ce4abc6ff1
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofweek
+description: RangeError thrown if time zone reports an offset that is out of range
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+[-86400_000_000_000, 86400_000_000_000].forEach((wrongOffset) => {
+ const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset);
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ assert.throws(RangeError, () => calendar.dayOfWeek(datetime));
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js
new file mode 100644
index 0000000000..6a323edffb
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofweek
+description: TypeError thrown if time zone reports an offset that is not a Number
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+[
+ undefined,
+ null,
+ true,
+ "+01:00",
+ Symbol(),
+ 3600_000_000_000n,
+ {},
+ { valueOf() { return 3600_000_000_000; } },
+].forEach((wrongOffset) => {
+ const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset);
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ assert.throws(TypeError, () => calendar.dayOfWeek(datetime));
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/basic.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/basic.js
new file mode 100644
index 0000000000..8bfdd06ac6
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/basic.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofweek
+description: Basic tests for dayOfWeek().
+features: [Temporal]
+---*/
+
+const iso = Temporal.Calendar.from("iso8601");
+const res = 6;
+assert.sameValue(iso.dayOfWeek(Temporal.PlainDate.from("1994-11-05")), res, "PlainDate");
+assert.sameValue(iso.dayOfWeek(Temporal.PlainDateTime.from("1994-11-05T08:15:30")), res, "PlainDateTime");
+assert.sameValue(iso.dayOfWeek({ year: 1994, month: 11, day: 5 }), res, "property bag");
+assert.sameValue(iso.dayOfWeek("1994-11-05"), res, "string");
+assert.throws(TypeError, () => iso.dayOfWeek({ year: 2000 }), "property bag with missing properties");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/branding.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/branding.js
new file mode 100644
index 0000000000..5be07e2a66
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/branding.js
@@ -0,0 +1,27 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofweek
+description: Throw a TypeError if the receiver is invalid
+features: [Symbol, Temporal]
+---*/
+
+const dayOfWeek = Temporal.Calendar.prototype.dayOfWeek;
+
+assert.sameValue(typeof dayOfWeek, "function");
+
+const args = [new Temporal.PlainDate(2000, 1, 1)];
+
+assert.throws(TypeError, () => dayOfWeek.apply(undefined, args), "undefined");
+assert.throws(TypeError, () => dayOfWeek.apply(null, args), "null");
+assert.throws(TypeError, () => dayOfWeek.apply(true, args), "true");
+assert.throws(TypeError, () => dayOfWeek.apply("", args), "empty string");
+assert.throws(TypeError, () => dayOfWeek.apply(Symbol(), args), "symbol");
+assert.throws(TypeError, () => dayOfWeek.apply(1, args), "1");
+assert.throws(TypeError, () => dayOfWeek.apply({}, args), "plain object");
+assert.throws(TypeError, () => dayOfWeek.apply(Temporal.Calendar, args), "Temporal.Calendar");
+assert.throws(TypeError, () => dayOfWeek.apply(Temporal.Calendar.prototype, args), "Temporal.Calendar.prototype");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/browser.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/browser.js
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/builtin.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/builtin.js
new file mode 100644
index 0000000000..8c4c4565c3
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/builtin.js
@@ -0,0 +1,36 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofweek
+description: >
+ Tests that Temporal.Calendar.prototype.dayOfWeek
+ meets the requirements for built-in objects defined by the
+ introduction of chapter 17 of the ECMAScript Language Specification.
+info: |
+ Built-in functions that are not constructors do not have a "prototype" property unless
+ otherwise specified in the description of a particular function.
+
+ Unless specified otherwise, a built-in object that is callable as a function is a built-in
+ function object with the characteristics described in 10.3. Unless specified otherwise, the
+ [[Extensible]] internal slot of a built-in object initially has the value true.
+
+ Unless otherwise specified every built-in function and every built-in constructor has the
+ Function prototype object [...] as the value of its [[Prototype]] internal slot.
+features: [Temporal]
+---*/
+
+assert.sameValue(Object.isExtensible(Temporal.Calendar.prototype.dayOfWeek),
+ true, "Built-in objects must be extensible.");
+
+assert.sameValue(Object.prototype.toString.call(Temporal.Calendar.prototype.dayOfWeek),
+ "[object Function]", "Object.prototype.toString");
+
+assert.sameValue(Object.getPrototypeOf(Temporal.Calendar.prototype.dayOfWeek),
+ Function.prototype, "prototype");
+
+assert.sameValue(Temporal.Calendar.prototype.dayOfWeek.hasOwnProperty("prototype"),
+ false, "prototype property");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/calendar-datefromfields-called-with-options-undefined.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/calendar-datefromfields-called-with-options-undefined.js
new file mode 100644
index 0000000000..a29e3f7263
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/calendar-datefromfields-called-with-options-undefined.js
@@ -0,0 +1,18 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofweek
+description: >
+ Calendar.dateFromFields method is called with undefined as the options value
+ when call originates internally
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions();
+calendar.dayOfWeek({ year: 2000, month: 5, day: 3, calendar });
+assert.sameValue(calendar.dateFromFieldsCallCount, 1);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/calendar-fields-iterable.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/calendar-fields-iterable.js
new file mode 100644
index 0000000000..d608137f82
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/calendar-fields-iterable.js
@@ -0,0 +1,35 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofweek
+description: Verify the result of calendar.fields() is treated correctly.
+info: |
+ sec-temporal.calendar.prototype.dayofweek step 4:
+ 4. Let _date_ be ? ToTemporalDate(_dateOrDateTime_).
+ sec-temporal-totemporaldate step 2.c:
+ c. Let _fieldNames_ be ? CalendarFields(_calendar_, « *"day"*, *"month"*, *"monthCode"*, *"year"* »).
+ sec-temporal-calendarfields step 4:
+ 4. Let _result_ be ? IterableToListOfType(_fieldsArray_, « String »).
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const expected = [
+ "day",
+ "month",
+ "monthCode",
+ "year",
+];
+
+const calendar1 = TemporalHelpers.calendarFieldsIterable();
+const calendar2 = TemporalHelpers.calendarFieldsIterable();
+calendar1.dayOfWeek({ year: 2000, month: 5, day: 2, calendar: calendar2 });
+
+assert.sameValue(calendar1.fieldsCallCount, 0, "fields() method not called");
+assert.sameValue(calendar2.fieldsCallCount, 1, "fields() method called once");
+assert.compareArray(calendar2.fieldsCalledWith[0], expected, "fields() method called with correct args");
+assert(calendar2.iteratorExhausted[0], "iterated through the whole iterable");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/calendar-temporal-object.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/calendar-temporal-object.js
new file mode 100644
index 0000000000..68c013a000
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/calendar-temporal-object.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofweek
+description: Fast path for converting other Temporal objects to Temporal.Calendar by reading internal slots
+info: |
+ sec-temporal.calendar.prototype.dayofweek step 4:
+ 4. Let _date_ be ? ToTemporalDate(_dateOrDateTime_).
+ sec-temporal-totemporaldate step 2.c:
+ c. Let _calendar_ be ? GetTemporalCalendarWithISODefault(_item_).
+ sec-temporal-gettemporalcalendarwithisodefault step 2:
+ 2. Return ? ToTemporalCalendarWithISODefault(_calendar_).
+ sec-temporal-totemporalcalendarwithisodefault step 2:
+ 3. Return ? ToTemporalCalendar(_temporalCalendarLike_).
+ sec-temporal-totemporalcalendar step 1.a:
+ a. If _temporalCalendarLike_ has an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]], [[InitializedTemporalMonthDay]], [[InitializedTemporalYearMonth]], or [[InitializedTemporalZonedDateTime]] internal slot, then
+ i. Return _temporalCalendarLike_.[[Calendar]].
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+TemporalHelpers.checkToTemporalCalendarFastPath((temporalObject) => {
+ const calendar = new Temporal.Calendar("iso8601");
+ calendar.dayOfWeek({ year: 2000, month: 5, day: 2, calendar: temporalObject });
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/infinity-throws-rangeerror.js
new file mode 100644
index 0000000000..3ca706358b
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/infinity-throws-rangeerror.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: Throws if any value in the property bag is Infinity or -Infinity
+esid: sec-temporal.calendar.prototype.dayofweek
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+const base = { year: 2000, month: 5, day: 2 };
+
+[Infinity, -Infinity].forEach((inf) => {
+ ["year", "month", "day"].forEach((prop) => {
+ assert.throws(RangeError, () => instance.dayOfWeek({ ...base, [prop]: inf }), `${prop} property cannot be ${inf}`);
+
+ const calls = [];
+ const obj = TemporalHelpers.toPrimitiveObserver(calls, inf, prop);
+ assert.throws(RangeError, () => instance.dayOfWeek({ ...base, [prop]: obj }));
+ assert.compareArray(calls, [`get ${prop}.valueOf`, `call ${prop}.valueOf`], "it fails after fetching the primitive value");
+ });
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/length.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/length.js
new file mode 100644
index 0000000000..0d2a913dcf
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/length.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2020 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofweek
+description: Temporal.Calendar.prototype.dayOfWeek.length is 1
+info: |
+ Every built-in function object, including constructors, has a "length" property whose value is
+ an integer. Unless otherwise specified, this value is equal to the largest number of named
+ arguments shown in the subclause headings for the function description. Optional parameters
+ (which are indicated with brackets: [ ]) or rest parameters (which are shown using the form
+ «...name») are not included in the default argument count.
+
+ Unless otherwise specified, the "length" property of a built-in function object has the
+ attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+verifyProperty(Temporal.Calendar.prototype.dayOfWeek, "length", {
+ value: 1,
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/name.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/name.js
new file mode 100644
index 0000000000..f5b9970e0d
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/name.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofweek
+description: Temporal.Calendar.prototype.dayOfWeek.name is "dayOfWeek".
+info: |
+ Every built-in function object, including constructors, that is not identified as an anonymous
+ function has a "name" property whose value is a String. Unless otherwise specified, this value
+ is the name that is given to the function in this specification.
+
+ Unless otherwise specified, the "name" property of a built-in function object, if it exists,
+ has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+verifyProperty(Temporal.Calendar.prototype.dayOfWeek, "name", {
+ value: "dayOfWeek",
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/not-a-constructor.js
new file mode 100644
index 0000000000..9c78acd845
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/not-a-constructor.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofweek
+description: >
+ Temporal.Calendar.prototype.dayOfWeek does not implement [[Construct]], is not new-able
+info: |
+ Built-in function objects that are not identified as constructors do not implement the
+ [[Construct]] internal method unless otherwise specified in the description of a particular
+ function.
+includes: [isConstructor.js]
+features: [Reflect.construct, Temporal]
+---*/
+
+assert.throws(TypeError, () => {
+ new Temporal.Calendar.prototype.dayOfWeek();
+}, "Calling as constructor");
+
+assert.sameValue(isConstructor(Temporal.Calendar.prototype.dayOfWeek), false,
+ "isConstructor(Temporal.Calendar.prototype.dayOfWeek)");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/plain-date-time.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/plain-date-time.js
new file mode 100644
index 0000000000..9d039cbe62
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/plain-date-time.js
@@ -0,0 +1,40 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.dayofweek
+description: >
+ Temporal.Calendar.prototype.dayOfWeek will take Temporal.PlainDateTime objects
+ and return the day of week.
+info: |
+ 5. Return 𝔽(! ToISODayOfWeek(temporalDate.[[ISOYear]], temporalDate.[[ISOMonth]], temporalDate.[[ISODay]])).
+features: [Temporal]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+let dt = new Temporal.PlainDateTime(1997, 1, 23, 5, 30, 13);
+assert.sameValue(
+ cal.dayOfWeek(dt),
+ 4,
+ 'cal.dayOfWeek(new Temporal.PlainDateTime(1997, 1, 23, 5, 30, 13)) must return 4'
+);
+dt = new Temporal.PlainDateTime(1996, 2, 23, 5, 30, 13);
+assert.sameValue(
+ cal.dayOfWeek(dt),
+ 5,
+ 'cal.dayOfWeek(new Temporal.PlainDateTime(1996, 2, 23, 5, 30, 13)) must return 5'
+);
+dt = new Temporal.PlainDateTime(1997, 2, 23, 5, 30, 13);
+assert.sameValue(
+ cal.dayOfWeek(dt),
+ 7,
+ 'cal.dayOfWeek(new Temporal.PlainDateTime(1997, 2, 23, 5, 30, 13)) must return 7'
+);
+dt = new Temporal.PlainDateTime(1997, 6, 23, 5, 30, 13);
+assert.sameValue(
+ cal.dayOfWeek(dt),
+ 1,
+ 'cal.dayOfWeek(new Temporal.PlainDateTime(1997, 6, 23, 5, 30, 13)) must return 1'
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/plain-date.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/plain-date.js
new file mode 100644
index 0000000000..4fbf36f474
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/plain-date.js
@@ -0,0 +1,22 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.dayofweek
+description: >
+ Temporal.Calendar.prototype.dayOfWeek will take Temporal.PlainDate objects
+ and return the day of week.
+info: |
+ 5. Return 𝔽(! ToISODayOfWeek(temporalDate.[[ISOYear]], temporalDate.[[ISOMonth]], temporalDate.[[ISODay]])).
+features: [Temporal]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+let d = new Temporal.PlainDate(1970, 1, 1);
+assert.sameValue(4, cal.dayOfWeek(d), '4 must return the same value returned by cal.dayOfWeek(d)');
+d = new Temporal.PlainDate(2021, 2, 15);
+assert.sameValue(1, cal.dayOfWeek(d), '1 must return the same value returned by cal.dayOfWeek(d)');
+d = new Temporal.PlainDate(2021, 8, 15);
+assert.sameValue(7, cal.dayOfWeek(d), '7 must return the same value returned by cal.dayOfWeek(d)');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/prop-desc.js
new file mode 100644
index 0000000000..a0b9027a05
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/prop-desc.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofweek
+description: The "dayOfWeek" property of Temporal.Calendar.prototype
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+assert.sameValue(
+ typeof Temporal.Calendar.prototype.dayOfWeek,
+ "function",
+ "`typeof Calendar.prototype.dayOfWeek` is `function`"
+);
+
+verifyProperty(Temporal.Calendar.prototype, "dayOfWeek", {
+ writable: true,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/shell.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/shell.js
new file mode 100644
index 0000000000..eda1477282
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/shell.js
@@ -0,0 +1,24 @@
+// GENERATED, DO NOT EDIT
+// file: isConstructor.js
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: |
+ Test if a given function is a constructor function.
+defines: [isConstructor]
+features: [Reflect.construct]
+---*/
+
+function isConstructor(f) {
+ if (typeof f !== "function") {
+ throw new Test262Error("isConstructor invoked with a non-function value");
+ }
+
+ try {
+ Reflect.construct(function(){}, [], f);
+ } catch (e) {
+ return false;
+ }
+ return true;
+}
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/string.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/string.js
new file mode 100644
index 0000000000..fe93ad4d4e
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/string.js
@@ -0,0 +1,21 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.dayofweek
+description: >
+ Temporal.Calendar.prototype.dayOfWeek will take ISO8601 string
+ and return the day of week.
+info: |
+ 4. Let temporalDate be ? ToTemporalDate(temporalDateLike).
+ 5. Return 𝔽(! ToISODayOfWeek(temporalDate.[[ISOYear]], temporalDate.[[ISOMonth]], temporalDate.[[ISODay]])).
+features: [Temporal]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+assert.sameValue(cal.dayOfWeek("2019-01-18"), 5, 'cal.dayOfWeek("2019-01-18") must return 5');
+assert.sameValue(cal.dayOfWeek("2019-03-18"), 1, 'cal.dayOfWeek("2019-03-18") must return 1');
+assert.sameValue(cal.dayOfWeek("2019-05-18"), 6, 'cal.dayOfWeek("2019-05-18") must return 6');
+assert.sameValue(cal.dayOfWeek("2019-08-18"), 7, 'cal.dayOfWeek("2019-08-18") must return 7');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/throw-range-error-ToTemporalDate.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/throw-range-error-ToTemporalDate.js
new file mode 100644
index 0000000000..6c435f930d
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/throw-range-error-ToTemporalDate.js
@@ -0,0 +1,18 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.dayOfWeek
+description: >
+ Temporal.Calendar.prototype.dayOfWeek throws RangeError on
+ ToTemporalDate when temporalDateLike is invalid string.
+info: |
+ 4. Let temporalDate be ? ToTemporalDate(temporalDateLike).
+features: [Temporal, arrow-function]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+assert.throws(RangeError, () => cal.dayOfWeek("invalid string"),
+ 'cal.dayOfWeek("invalid string") throws a RangeError exception');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/year-zero.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/year-zero.js
new file mode 100644
index 0000000000..fadd2ebc31
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfWeek/year-zero.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofweek
+description: Negative zero, as an extended year, is rejected
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ "-000000-10-31",
+ "-000000-10-31T00:45",
+ "-000000-10-31T00:45+01:00",
+ "-000000-10-31T00:45+00:00[UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.dayOfWeek(arg),
+ "reject minus zero as extended year"
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-builtin-calendar-no-array-iteration.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-builtin-calendar-no-array-iteration.js
new file mode 100644
index 0000000000..dd7cea23e4
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-builtin-calendar-no-array-iteration.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofyear
+description: >
+ Calling the method with a property bag argument with a builtin calendar causes
+ no observable array iteration when getting the calendar fields.
+features: [Temporal]
+---*/
+
+const arrayPrototypeSymbolIteratorOriginal = Array.prototype[Symbol.iterator];
+Array.prototype[Symbol.iterator] = function arrayIterator() {
+ throw new Test262Error("Array should not be iterated");
+}
+
+const instance = new Temporal.Calendar("iso8601");
+const arg = { year: 2000, month: 5, day: 2, calendar: "iso8601" };
+instance.dayOfYear(arg);
+
+Array.prototype[Symbol.iterator] = arrayPrototypeSymbolIteratorOriginal;
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-calendar-datefromfields-called-with-null-prototype-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-calendar-datefromfields-called-with-null-prototype-fields.js
new file mode 100644
index 0000000000..9520c825bd
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-calendar-datefromfields-called-with-null-prototype-fields.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofyear
+description: >
+ Calendar.dateFromFields method is called with a null-prototype fields object
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarCheckFieldsPrototypePollution();
+const instance = new Temporal.Calendar("iso8601");
+const arg = { year: 2000, month: 5, day: 2, calendar };
+instance.dayOfYear(arg);
+assert.sameValue(calendar.dateFromFieldsCallCount, 1, "dateFromFields should be called on the property bag's calendar");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-constructor-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-constructor-in-calendar-fields.js
new file mode 100644
index 0000000000..559093bf44
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-constructor-in-calendar-fields.js
@@ -0,0 +1,17 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.dayofyear
+description: If a calendar's fields() method returns a field named 'constructor', PrepareTemporalFields should throw a RangeError.
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarWithExtraFields(['constructor']);
+const arg = {year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar};
+const instance = new Temporal.Calendar("iso8601");
+
+assert.throws(RangeError, () => instance.dayOfYear(arg));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-duplicate-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-duplicate-calendar-fields.js
new file mode 100644
index 0000000000..c8c47a6454
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-duplicate-calendar-fields.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.dayofyear
+description: If a calendar's fields() method returns duplicate field names, PrepareTemporalFields should throw a RangeError.
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+for (const extra_fields of [['foo', 'foo'], ['day'], ['month'], ['monthCode'], ['year']]) {
+ const calendar = TemporalHelpers.calendarWithExtraFields(extra_fields);
+ const arg = { year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar };
+ const instance = new Temporal.Calendar("iso8601");
+
+ assert.throws(RangeError, () => instance.dayOfYear(arg));
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-leap-second.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-leap-second.js
new file mode 100644
index 0000000000..d9dbd26e92
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-leap-second.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofyear
+description: Leap second is a valid ISO string for PlainDate
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+let arg = "2016-12-31T23:59:60";
+const result1 = instance.dayOfYear(arg);
+assert.sameValue(
+ result1,
+ 366,
+ "leap second is a valid ISO string for PlainDate"
+);
+
+arg = { year: 2016, month: 12, day: 31, hour: 23, minute: 59, second: 60 };
+const result2 = instance.dayOfYear(arg);
+assert.sameValue(
+ result2,
+ 366,
+ "second: 60 is ignored in property bag for PlainDate"
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-number.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-number.js
new file mode 100644
index 0000000000..b2c92dc6e5
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-number.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofyear
+description: A number cannot be used in place of a Temporal.PlainDate
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const numbers = [
+ 1,
+ 19761118,
+ -19761118,
+ 1234567890,
+];
+
+for (const arg of numbers) {
+ assert.throws(
+ TypeError,
+ () => instance.dayOfYear(arg),
+ 'Numbers cannot be used in place of an ISO string for PlainDate'
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-propertybag-calendar-case-insensitive.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-propertybag-calendar-case-insensitive.js
new file mode 100644
index 0000000000..1123d096e3
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-propertybag-calendar-case-insensitive.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofyear
+description: The calendar name is case-insensitive
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const calendar = "IsO8601";
+
+const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+const result = instance.dayOfYear(arg);
+assert.sameValue(result, 323, "Calendar is case-insensitive");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-propertybag-calendar-leap-second.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-propertybag-calendar-leap-second.js
new file mode 100644
index 0000000000..ec673db6fd
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-propertybag-calendar-leap-second.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofyear
+description: Leap second is a valid ISO string for a calendar in a property bag
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const calendar = "2016-12-31T23:59:60";
+
+const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+const result = instance.dayOfYear(arg);
+assert.sameValue(
+ result,
+ 323,
+ "leap second is a valid ISO string for calendar"
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-propertybag-calendar-number.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-propertybag-calendar-number.js
new file mode 100644
index 0000000000..bc418cddab
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-propertybag-calendar-number.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofyear
+description: A number as calendar in a property bag is not accepted
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const numbers = [
+ 1,
+ 19970327,
+ -19970327,
+ 1234567890,
+];
+
+for (const calendar of numbers) {
+ const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+ assert.throws(
+ TypeError,
+ () => instance.dayOfYear(arg),
+ "Numbers cannot be used as a calendar"
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-propertybag-calendar-string.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-propertybag-calendar-string.js
new file mode 100644
index 0000000000..91ebe03687
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-propertybag-calendar-string.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofyear
+description: A calendar ID is valid input for Calendar
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const calendar = "iso8601";
+
+const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+const result = instance.dayOfYear(arg);
+assert.sameValue(result, 323, `Calendar created from string "${calendar}"`);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-propertybag-calendar-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-propertybag-calendar-wrong-type.js
new file mode 100644
index 0000000000..7130706abb
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-propertybag-calendar-wrong-type.js
@@ -0,0 +1,46 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofyear
+description: >
+ Appropriate error thrown when a calendar property from a property bag cannot
+ be converted to a calendar object or string
+features: [BigInt, Symbol, Temporal]
+---*/
+
+const timeZone = new Temporal.TimeZone("UTC");
+const instance = new Temporal.Calendar("iso8601");
+
+const primitiveTests = [
+ [null, "null"],
+ [true, "boolean"],
+ ["", "empty string"],
+ [1, "number that doesn't convert to a valid ISO string"],
+ [1n, "bigint"],
+];
+
+for (const [calendar, description] of primitiveTests) {
+ const arg = { year: 2019, monthCode: "M11", day: 1, calendar };
+ assert.throws(
+ typeof calendar === 'string' ? RangeError : TypeError,
+ () => instance.dayOfYear(arg),
+ `${description} does not convert to a valid ISO string`
+ );
+}
+
+const typeErrorTests = [
+ [Symbol(), "symbol"],
+ [{}, "plain object that doesn't implement the protocol"],
+ [new Temporal.TimeZone("UTC"), "time zone instance"],
+ [Temporal.Calendar, "Temporal.Calendar, object"],
+ [Temporal.Calendar.prototype, "Temporal.Calendar.prototype, object"], // fails brand check in dateFromFields()
+];
+
+for (const [calendar, description] of typeErrorTests) {
+ const arg = { year: 2019, monthCode: "M11", day: 1, calendar };
+ assert.throws(TypeError, () => instance.dayOfYear(arg), `${description} is not a valid property bag and does not convert to a string`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-propertybag-calendar-year-zero.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-propertybag-calendar-year-zero.js
new file mode 100644
index 0000000000..7f06c31917
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-propertybag-calendar-year-zero.js
@@ -0,0 +1,27 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofyear
+description: Negative zero, as an extended year, is rejected
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ "-000000-10-31",
+ "-000000-10-31T17:45",
+ "-000000-10-31T17:45Z",
+ "-000000-10-31T17:45+01:00",
+ "-000000-10-31T17:45+00:00[UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.dayOfYear(arg),
+ "reject minus zero as extended year"
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-proto-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-proto-in-calendar-fields.js
new file mode 100644
index 0000000000..829564e665
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-proto-in-calendar-fields.js
@@ -0,0 +1,17 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.dayofyear
+description: If a calendar's fields() method returns a field named '__proto__', PrepareTemporalFields should throw a RangeError.
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarWithExtraFields(['__proto__']);
+const arg = {year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar};
+const instance = new Temporal.Calendar("iso8601");
+
+assert.throws(RangeError, () => instance.dayOfYear(arg));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-string-calendar-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-string-calendar-annotation.js
new file mode 100644
index 0000000000..09956daf3a
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-string-calendar-annotation.js
@@ -0,0 +1,33 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofyear
+description: Various forms of calendar annotation; critical flag has no effect
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02[u-ca=iso8601]", "without time or time zone"],
+ ["2000-05-02[UTC][u-ca=iso8601]", "with time zone and no time"],
+ ["2000-05-02T15:23[u-ca=iso8601]", "without time zone"],
+ ["2000-05-02T15:23[UTC][u-ca=iso8601]", "with time zone"],
+ ["2000-05-02T15:23[!u-ca=iso8601]", "with ! and no time zone"],
+ ["2000-05-02T15:23[UTC][!u-ca=iso8601]", "with ! and time zone"],
+ ["2000-05-02T15:23[u-ca=iso8601][u-ca=discord]", "second annotation ignored"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.dayOfYear(arg);
+
+ assert.sameValue(
+ result,
+ 123,
+ `calendar annotation (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-string-critical-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-string-critical-unknown-annotation.js
new file mode 100644
index 0000000000..48b3724340
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-string-critical-unknown-annotation.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofyear
+description: Unknown annotations with critical flag are rejected
+features: [Temporal]
+---*/
+
+const invalidStrings = [
+ "1970-01-01[!foo=bar]",
+ "1970-01-01T00:00[!foo=bar]",
+ "1970-01-01T00:00[UTC][!foo=bar]",
+ "1970-01-01T00:00[u-ca=iso8601][!foo=bar]",
+ "1970-01-01T00:00[UTC][!foo=bar][u-ca=iso8601]",
+ "1970-01-01T00:00[foo=bar][!_foo-bar0=Dont-Ignore-This-99999999999]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.dayOfYear(arg),
+ `reject unknown annotation with critical flag: ${arg}`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-string-date-with-utc-offset.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-string-date-with-utc-offset.js
new file mode 100644
index 0000000000..445ee6aeff
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-string-date-with-utc-offset.js
@@ -0,0 +1,48 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofyear
+description: UTC offset not valid with format that does not include a time
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const validStrings = [
+ "2000-05-02T00+00:00",
+ "2000-05-02T00+00:00[UTC]",
+ "2000-05-02T00+00:00[!UTC]",
+ "2000-05-02T00-02:30[America/St_Johns]",
+];
+
+for (const arg of validStrings) {
+ const result = instance.dayOfYear(arg);
+
+ assert.sameValue(
+ result,
+ 123,
+ `"${arg}" is a valid UTC offset with time for PlainDate`
+ );
+}
+
+const invalidStrings = [
+ "2022-09-15Z",
+ "2022-09-15Z[UTC]",
+ "2022-09-15Z[Europe/Vienna]",
+ "2022-09-15+00:00",
+ "2022-09-15+00:00[UTC]",
+ "2022-09-15-02:30",
+ "2022-09-15-02:30[America/St_Johns]",
+];
+
+for (const arg of invalidStrings) {
+ assert.throws(
+ RangeError,
+ () => instance.dayOfYear(arg),
+ `"${arg}" UTC offset without time is not valid for PlainDate`
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-string-invalid.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-string-invalid.js
new file mode 100644
index 0000000000..37167a97d6
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-string-invalid.js
@@ -0,0 +1,64 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofyear
+description: >
+ RangeError thrown if an invalid ISO string (or syntactically valid ISO string
+ that is not supported) is used as a PlainDate
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ // invalid ISO strings:
+ "",
+ "invalid iso8601",
+ "2020-01-00",
+ "2020-01-32",
+ "2020-02-30",
+ "2021-02-29",
+ "2020-00-01",
+ "2020-13-01",
+ "2020-01-01T",
+ "2020-01-01T25:00:00",
+ "2020-01-01T01:60:00",
+ "2020-01-01T01:60:61",
+ "2020-01-01junk",
+ "2020-01-01T00:00:00junk",
+ "2020-01-01T00:00:00+00:00junk",
+ "2020-01-01T00:00:00+00:00[UTC]junk",
+ "2020-01-01T00:00:00+00:00[UTC][u-ca=iso8601]junk",
+ "02020-01-01",
+ "2020-001-01",
+ "2020-01-001",
+ "2020-01-01T001",
+ "2020-01-01T01:001",
+ "2020-01-01T01:01:001",
+ // valid, but forms not supported in Temporal:
+ "2020-W01-1",
+ "2020-001",
+ "+0002020-01-01",
+ // valid, but this calendar must not exist:
+ "2020-01-01[u-ca=notexist]",
+ // may be valid in other contexts, but insufficient information for PlainDate:
+ "2020-01",
+ "+002020-01",
+ "01-01",
+ "2020-W01",
+ "P1Y",
+ "-P12Y",
+ // valid, but outside the supported range:
+ "-999999-01-01",
+ "+999999-01-01",
+];
+const instance = new Temporal.Calendar("iso8601");
+for (const arg of invalidStrings) {
+ assert.throws(
+ RangeError,
+ () => instance.dayOfYear(arg),
+ `"${arg}" should not be a valid ISO string for a PlainDate`
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-string-multiple-calendar.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-string-multiple-calendar.js
new file mode 100644
index 0000000000..e8b2714c5c
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-string-multiple-calendar.js
@@ -0,0 +1,32 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofyear
+description: >
+ More than one calendar annotation is not syntactical if any have the criical
+ flag
+features: [Temporal]
+---*/
+
+const invalidStrings = [
+ "1970-01-01[u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01[!u-ca=iso8601][u-ca=iso8601]",
+ "1970-01-01[UTC][u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01[u-ca=iso8601][foo=bar][!u-ca=iso8601]",
+ "1970-01-01T00:00[u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01T00:00[!u-ca=iso8601][u-ca=iso8601]",
+ "1970-01-01T00:00[UTC][u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01T00:00[u-ca=iso8601][foo=bar][!u-ca=iso8601]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.dayOfYear(arg),
+ `reject more than one calendar annotation if any critical: ${arg}`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-string-multiple-time-zone.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-string-multiple-time-zone.js
new file mode 100644
index 0000000000..38dc81a454
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-string-multiple-time-zone.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofyear
+description: More than one time zone annotation is not syntactical
+features: [Temporal]
+---*/
+
+const invalidStrings = [
+ "1970-01-01[UTC][UTC]",
+ "1970-01-01T00:00[UTC][UTC]",
+ "1970-01-01T00:00[!UTC][UTC]",
+ "1970-01-01T00:00[UTC][!UTC]",
+ "1970-01-01T00:00[UTC][u-ca=iso8601][UTC]",
+ "1970-01-01T00:00[UTC][foo=bar][UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.dayOfYear(arg),
+ `reject more than one time zone annotation: ${arg}`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-string-time-separators.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-string-time-separators.js
new file mode 100644
index 0000000000..6399c49752
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-string-time-separators.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofyear
+description: Time separator in string argument can vary
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02T15:23", "uppercase T"],
+ ["2000-05-02t15:23", "lowercase T"],
+ ["2000-05-02 15:23", "space between date and time"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.dayOfYear(arg);
+
+ assert.sameValue(
+ result,
+ 123,
+ `variant time separators (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-string-time-zone-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-string-time-zone-annotation.js
new file mode 100644
index 0000000000..e266fc22f5
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-string-time-zone-annotation.js
@@ -0,0 +1,38 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofyear
+description: Various forms of time zone annotation; critical flag has no effect
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02[Asia/Kolkata]", "named, with no time"],
+ ["2000-05-02[!Europe/Vienna]", "named, with ! and no time"],
+ ["2000-05-02[+00:00]", "numeric, with no time"],
+ ["2000-05-02[!-02:30]", "numeric, with ! and no time"],
+ ["2000-05-02T15:23[America/Sao_Paulo]", "named, with no offset"],
+ ["2000-05-02T15:23[!Asia/Tokyo]", "named, with ! and no offset"],
+ ["2000-05-02T15:23[-02:30]", "numeric, with no offset"],
+ ["2000-05-02T15:23[!+00:00]", "numeric, with ! and no offset"],
+ ["2000-05-02T15:23+00:00[America/New_York]", "named, with offset"],
+ ["2000-05-02T15:23+00:00[!UTC]", "named, with offset and !"],
+ ["2000-05-02T15:23+00:00[+01:00]", "numeric, with offset"],
+ ["2000-05-02T15:23+00:00[!-08:00]", "numeric, with offset and !"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.dayOfYear(arg);
+
+ assert.sameValue(
+ result,
+ 123,
+ `time zone annotation (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-string-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-string-unknown-annotation.js
new file mode 100644
index 0000000000..e7edf6df42
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-string-unknown-annotation.js
@@ -0,0 +1,32 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofyear
+description: Various forms of unknown annotation
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02[foo=bar]", "without time"],
+ ["2000-05-02T15:23[foo=bar]", "alone"],
+ ["2000-05-02T15:23[UTC][foo=bar]", "with time zone"],
+ ["2000-05-02T15:23[u-ca=iso8601][foo=bar]", "with calendar"],
+ ["2000-05-02T15:23[UTC][foo=bar][u-ca=iso8601]", "with time zone and calendar"],
+ ["2000-05-02T15:23[foo=bar][_foo-bar0=Ignore-This-999999999999]", "with another unknown annotation"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.dayOfYear(arg);
+
+ assert.sameValue(
+ result,
+ 123,
+ `unknown annotation (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-string-with-utc-designator.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-string-with-utc-designator.js
new file mode 100644
index 0000000000..e0ee9879bc
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-string-with-utc-designator.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofyear
+description: RangeError thrown if a string with UTC designator is used as a PlainDate
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ "2019-10-01T09:00:00Z",
+ "2019-10-01T09:00:00Z[UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.dayOfYear(arg),
+ "String with UTC designator should not be valid as a PlainDate"
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-wrong-type.js
new file mode 100644
index 0000000000..d607a28071
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-wrong-type.js
@@ -0,0 +1,43 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofyear
+description: >
+ Appropriate error thrown when argument cannot be converted to a valid string
+ or property bag for PlainDate
+features: [BigInt, Symbol, Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const primitiveTests = [
+ [undefined, "undefined"],
+ [null, "null"],
+ [true, "boolean"],
+ ["", "empty string"],
+ [1, "number that doesn't convert to a valid ISO string"],
+ [1n, "bigint"],
+];
+
+for (const [arg, description] of primitiveTests) {
+ assert.throws(
+ typeof arg === 'string' ? RangeError : TypeError,
+ () => instance.dayOfYear(arg),
+ `${description} does not convert to a valid ISO string`
+ );
+}
+
+const typeErrorTests = [
+ [Symbol(), "symbol"],
+ [{}, "plain object"],
+ [Temporal.PlainDate, "Temporal.PlainDate, object"],
+ [Temporal.PlainDate.prototype, "Temporal.PlainDate.prototype, object"],
+];
+
+for (const [arg, description] of typeErrorTests) {
+ assert.throws(TypeError, () => instance.dayOfYear(arg), `${description} is not a valid property bag and does not convert to a string`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-zoneddatetime-convert.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-zoneddatetime-convert.js
new file mode 100644
index 0000000000..fda318c39a
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-zoneddatetime-convert.js
@@ -0,0 +1,22 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofyear
+description: An exception from TimeZone#getOffsetNanosecondsFor() is propagated.
+features: [Temporal]
+---*/
+
+class TZ extends Temporal.TimeZone {
+ constructor() { super("UTC") }
+ getOffsetNanosecondsFor() { throw new Test262Error() }
+}
+
+const tz = new TZ();
+const arg = new Temporal.ZonedDateTime(0n, tz);
+const instance = new Temporal.Calendar("iso8601");
+
+assert.throws(Test262Error, () => instance.dayOfYear(arg));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-zoneddatetime-slots.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-zoneddatetime-slots.js
new file mode 100644
index 0000000000..39bcc444b8
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-zoneddatetime-slots.js
@@ -0,0 +1,40 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofyear
+description: Getters are not called when converting a ZonedDateTime to a PlainDate.
+includes: [compareArray.js]
+features: [Temporal]
+---*/
+
+const actual = [];
+const prototypeDescrs = Object.getOwnPropertyDescriptors(Temporal.ZonedDateTime.prototype);
+const getters = ["year", "month", "monthCode", "day", "hour", "minute", "second", "millisecond", "microsecond", "nanosecond", "calendar"];
+
+for (const property of getters) {
+ Object.defineProperty(Temporal.ZonedDateTime.prototype, property, {
+ get() {
+ actual.push(`get ${property}`);
+ const value = prototypeDescrs[property].get.call(this);
+ return {
+ toString() {
+ actual.push(`toString ${property}`);
+ return value.toString();
+ },
+ valueOf() {
+ actual.push(`valueOf ${property}`);
+ return value;
+ },
+ };
+ },
+ });
+}
+
+const arg = new Temporal.ZonedDateTime(0n, "UTC");
+const instance = new Temporal.Calendar("iso8601");
+instance.dayOfYear(arg);
+assert.compareArray(actual, []);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js
new file mode 100644
index 0000000000..efbbd704cd
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofyear
+description: RangeError thrown if time zone reports an offset that is not an integer number of nanoseconds
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+[3600_000_000_000.5, NaN, -Infinity, Infinity].forEach((wrongOffset) => {
+ const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset);
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ assert.throws(RangeError, () => calendar.dayOfYear(datetime));
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js
new file mode 100644
index 0000000000..cca1006fd3
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofyear
+description: TypeError thrown if timeZone.getOffsetNanosecondsFor is not callable
+features: [BigInt, Symbol, Temporal, arrow-function]
+---*/
+
+[undefined, null, true, Math.PI, 'string', Symbol('sym'), 42n, {}].forEach((notCallable) => {
+ const timeZone = new Temporal.TimeZone("UTC");
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ timeZone.getOffsetNanosecondsFor = notCallable;
+ assert.throws(
+ TypeError,
+ () => calendar.dayOfYear(datetime),
+ `Uncallable ${notCallable === null ? 'null' : typeof notCallable} getOffsetNanosecondsFor should throw TypeError`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js
new file mode 100644
index 0000000000..d9b51556fe
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofyear
+description: RangeError thrown if time zone reports an offset that is out of range
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+[-86400_000_000_000, 86400_000_000_000].forEach((wrongOffset) => {
+ const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset);
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ assert.throws(RangeError, () => calendar.dayOfYear(datetime));
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js
new file mode 100644
index 0000000000..87c99d26c2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofyear
+description: TypeError thrown if time zone reports an offset that is not a Number
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+[
+ undefined,
+ null,
+ true,
+ "+01:00",
+ Symbol(),
+ 3600_000_000_000n,
+ {},
+ { valueOf() { return 3600_000_000_000; } },
+].forEach((wrongOffset) => {
+ const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset);
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ assert.throws(TypeError, () => calendar.dayOfYear(datetime));
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/basic.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/basic.js
new file mode 100644
index 0000000000..b391523d47
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/basic.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofyear
+description: Basic tests for dayOfYear().
+features: [Temporal]
+---*/
+
+const iso = Temporal.Calendar.from("iso8601");
+const res = 309;
+assert.sameValue(iso.dayOfYear(Temporal.PlainDate.from("1994-11-05")), res, "PlainDate");
+assert.sameValue(iso.dayOfYear(Temporal.PlainDateTime.from("1994-11-05T08:15:30")), res, "PlainDateTime");
+assert.sameValue(iso.dayOfYear({ year: 1994, month: 11, day: 5 }), res, "property bag");
+assert.sameValue(iso.dayOfYear("1994-11-05"), res, "string");
+assert.throws(TypeError, () => iso.dayOfYear({ year: 2000 }), "property bag with missing properties");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/branding.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/branding.js
new file mode 100644
index 0000000000..e20d743ae3
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/branding.js
@@ -0,0 +1,27 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofyear
+description: Throw a TypeError if the receiver is invalid
+features: [Symbol, Temporal]
+---*/
+
+const dayOfYear = Temporal.Calendar.prototype.dayOfYear;
+
+assert.sameValue(typeof dayOfYear, "function");
+
+const args = [new Temporal.PlainDate(2000, 1, 1)];
+
+assert.throws(TypeError, () => dayOfYear.apply(undefined, args), "undefined");
+assert.throws(TypeError, () => dayOfYear.apply(null, args), "null");
+assert.throws(TypeError, () => dayOfYear.apply(true, args), "true");
+assert.throws(TypeError, () => dayOfYear.apply("", args), "empty string");
+assert.throws(TypeError, () => dayOfYear.apply(Symbol(), args), "symbol");
+assert.throws(TypeError, () => dayOfYear.apply(1, args), "1");
+assert.throws(TypeError, () => dayOfYear.apply({}, args), "plain object");
+assert.throws(TypeError, () => dayOfYear.apply(Temporal.Calendar, args), "Temporal.Calendar");
+assert.throws(TypeError, () => dayOfYear.apply(Temporal.Calendar.prototype, args), "Temporal.Calendar.prototype");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/browser.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/browser.js
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/builtin.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/builtin.js
new file mode 100644
index 0000000000..8c5ea8047e
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/builtin.js
@@ -0,0 +1,36 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofyear
+description: >
+ Tests that Temporal.Calendar.prototype.dayOfYear
+ meets the requirements for built-in objects defined by the
+ introduction of chapter 17 of the ECMAScript Language Specification.
+info: |
+ Built-in functions that are not constructors do not have a "prototype" property unless
+ otherwise specified in the description of a particular function.
+
+ Unless specified otherwise, a built-in object that is callable as a function is a built-in
+ function object with the characteristics described in 10.3. Unless specified otherwise, the
+ [[Extensible]] internal slot of a built-in object initially has the value true.
+
+ Unless otherwise specified every built-in function and every built-in constructor has the
+ Function prototype object [...] as the value of its [[Prototype]] internal slot.
+features: [Temporal]
+---*/
+
+assert.sameValue(Object.isExtensible(Temporal.Calendar.prototype.dayOfYear),
+ true, "Built-in objects must be extensible.");
+
+assert.sameValue(Object.prototype.toString.call(Temporal.Calendar.prototype.dayOfYear),
+ "[object Function]", "Object.prototype.toString");
+
+assert.sameValue(Object.getPrototypeOf(Temporal.Calendar.prototype.dayOfYear),
+ Function.prototype, "prototype");
+
+assert.sameValue(Temporal.Calendar.prototype.dayOfYear.hasOwnProperty("prototype"),
+ false, "prototype property");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/calendar-datefromfields-called-with-options-undefined.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/calendar-datefromfields-called-with-options-undefined.js
new file mode 100644
index 0000000000..465e3b9c01
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/calendar-datefromfields-called-with-options-undefined.js
@@ -0,0 +1,18 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofyear
+description: >
+ Calendar.dateFromFields method is called with undefined as the options value
+ when call originates internally
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions();
+calendar.dayOfYear({ year: 2000, month: 5, day: 3, calendar });
+assert.sameValue(calendar.dateFromFieldsCallCount, 1);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/calendar-fields-iterable.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/calendar-fields-iterable.js
new file mode 100644
index 0000000000..1d794405c3
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/calendar-fields-iterable.js
@@ -0,0 +1,35 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofyear
+description: Verify the result of calendar.fields() is treated correctly.
+info: |
+ sec-temporal.calendar.prototype.dayofyear step 4:
+ 4. Let _date_ be ? ToTemporalDate(_dateOrDateTime_).
+ sec-temporal-totemporaldate step 2.c:
+ c. Let _fieldNames_ be ? CalendarFields(_calendar_, « *"day"*, *"month"*, *"monthCode"*, *"year"* »).
+ sec-temporal-calendarfields step 4:
+ 4. Let _result_ be ? IterableToListOfType(_fieldsArray_, « String »).
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const expected = [
+ "day",
+ "month",
+ "monthCode",
+ "year",
+];
+
+const calendar1 = TemporalHelpers.calendarFieldsIterable();
+const calendar2 = TemporalHelpers.calendarFieldsIterable();
+calendar1.dayOfYear({ year: 2000, month: 5, day: 2, calendar: calendar2 });
+
+assert.sameValue(calendar1.fieldsCallCount, 0, "fields() method not called");
+assert.sameValue(calendar2.fieldsCallCount, 1, "fields() method called once");
+assert.compareArray(calendar2.fieldsCalledWith[0], expected, "fields() method called with correct args");
+assert(calendar2.iteratorExhausted[0], "iterated through the whole iterable");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/calendar-temporal-object.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/calendar-temporal-object.js
new file mode 100644
index 0000000000..614b2cd72a
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/calendar-temporal-object.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofyear
+description: Fast path for converting other Temporal objects to Temporal.Calendar by reading internal slots
+info: |
+ sec-temporal.calendar.prototype.dayofyear step 4:
+ 4. Let _date_ be ? ToTemporalDate(_dateOrDateTime_).
+ sec-temporal-totemporaldate step 2.c:
+ c. Let _calendar_ be ? GetTemporalCalendarWithISODefault(_item_).
+ sec-temporal-gettemporalcalendarwithisodefault step 2:
+ 2. Return ? ToTemporalCalendarWithISODefault(_calendar_).
+ sec-temporal-totemporalcalendarwithisodefault step 2:
+ 3. Return ? ToTemporalCalendar(_temporalCalendarLike_).
+ sec-temporal-totemporalcalendar step 1.a:
+ a. If _temporalCalendarLike_ has an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]], [[InitializedTemporalMonthDay]], [[InitializedTemporalYearMonth]], or [[InitializedTemporalZonedDateTime]] internal slot, then
+ i. Return _temporalCalendarLike_.[[Calendar]].
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+TemporalHelpers.checkToTemporalCalendarFastPath((temporalObject) => {
+ const calendar = new Temporal.Calendar("iso8601");
+ calendar.dayOfYear({ year: 2000, month: 5, day: 2, calendar: temporalObject });
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/infinity-throws-rangeerror.js
new file mode 100644
index 0000000000..9594bb6ded
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/infinity-throws-rangeerror.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: Throws if any value in the property bag is Infinity or -Infinity
+esid: sec-temporal.calendar.prototype.dayofyear
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+const base = { year: 2000, month: 5, day: 2 };
+
+[Infinity, -Infinity].forEach((inf) => {
+ ["year", "month", "day"].forEach((prop) => {
+ assert.throws(RangeError, () => instance.dayOfYear({ ...base, [prop]: inf }), `${prop} property cannot be ${inf}`);
+
+ const calls = [];
+ const obj = TemporalHelpers.toPrimitiveObserver(calls, inf, prop);
+ assert.throws(RangeError, () => instance.dayOfYear({ ...base, [prop]: obj }));
+ assert.compareArray(calls, [`get ${prop}.valueOf`, `call ${prop}.valueOf`], "it fails after fetching the primitive value");
+ });
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/length.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/length.js
new file mode 100644
index 0000000000..005e044216
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/length.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2020 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofyear
+description: Temporal.Calendar.prototype.dayOfYear.length is 1
+info: |
+ Every built-in function object, including constructors, has a "length" property whose value is
+ an integer. Unless otherwise specified, this value is equal to the largest number of named
+ arguments shown in the subclause headings for the function description. Optional parameters
+ (which are indicated with brackets: [ ]) or rest parameters (which are shown using the form
+ «...name») are not included in the default argument count.
+
+ Unless otherwise specified, the "length" property of a built-in function object has the
+ attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+verifyProperty(Temporal.Calendar.prototype.dayOfYear, "length", {
+ value: 1,
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/name.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/name.js
new file mode 100644
index 0000000000..bc9dccc138
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/name.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofyear
+description: Temporal.Calendar.prototype.dayOfYear.name is "dayOfYear".
+info: |
+ Every built-in function object, including constructors, that is not identified as an anonymous
+ function has a "name" property whose value is a String. Unless otherwise specified, this value
+ is the name that is given to the function in this specification.
+
+ Unless otherwise specified, the "name" property of a built-in function object, if it exists,
+ has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+verifyProperty(Temporal.Calendar.prototype.dayOfYear, "name", {
+ value: "dayOfYear",
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/not-a-constructor.js
new file mode 100644
index 0000000000..b40bd8ee27
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/not-a-constructor.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofyear
+description: >
+ Temporal.Calendar.prototype.dayOfYear does not implement [[Construct]], is not new-able
+info: |
+ Built-in function objects that are not identified as constructors do not implement the
+ [[Construct]] internal method unless otherwise specified in the description of a particular
+ function.
+includes: [isConstructor.js]
+features: [Reflect.construct, Temporal]
+---*/
+
+assert.throws(TypeError, () => {
+ new Temporal.Calendar.prototype.dayOfYear();
+}, "Calling as constructor");
+
+assert.sameValue(isConstructor(Temporal.Calendar.prototype.dayOfYear), false,
+ "isConstructor(Temporal.Calendar.prototype.dayOfYear)");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/plain-date-time.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/plain-date-time.js
new file mode 100644
index 0000000000..58cc7d9670
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/plain-date-time.js
@@ -0,0 +1,58 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.dayofyear
+description: >
+ Temporal.Calendar.prototype.dayOfYear will take PlainDateTime object and
+ return the day of year.
+info: |
+ 4. Let temporalDate be ? ToTemporalDate(temporalDateLike).
+ 5. Return 𝔽(! ToISODayOfYear(temporalDate.[[ISOYear]], temporalDate.[[ISOMonth]], temporalDate.[[ISODay]])).
+features: [Temporal]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+let dt = new Temporal.PlainDateTime(1997, 1, 23, 5, 30, 13);
+assert.sameValue(
+ cal.dayOfYear(dt),
+ 23,
+ 'cal.dayOfYear(new Temporal.PlainDateTime(1997, 1, 23, 5, 30, 13)) must return 23'
+);
+
+dt = new Temporal.PlainDateTime(1997, 2, 23, 5, 30, 13);
+assert.sameValue(
+ cal.dayOfYear(dt),
+ 54,
+ 'cal.dayOfYear(new Temporal.PlainDateTime(1997, 2, 23, 5, 30, 13)) must return 54'
+);
+
+dt = new Temporal.PlainDateTime(1996, 3, 23, 5, 30, 13);
+assert.sameValue(
+ cal.dayOfYear(dt),
+ 83,
+ 'cal.dayOfYear(new Temporal.PlainDateTime(1996, 3, 23, 5, 30, 13)) must return 83'
+);
+
+dt = new Temporal.PlainDateTime(1997, 3, 23, 5, 30, 13);
+assert.sameValue(
+ cal.dayOfYear(dt),
+ 82,
+ 'cal.dayOfYear(new Temporal.PlainDateTime(1997, 3, 23, 5, 30, 13)) must return 82'
+);
+
+dt = new Temporal.PlainDateTime(1997, 12, 31, 5, 30, 13);
+assert.sameValue(
+ cal.dayOfYear(dt),
+ 365,
+ 'cal.dayOfYear(new Temporal.PlainDateTime(1997, 12, 31, 5, 30, 13)) must return 365'
+);
+
+dt = new Temporal.PlainDateTime(1996, 12, 31, 5, 30, 13);
+assert.sameValue(
+ cal.dayOfYear(dt),
+ 366,
+ 'cal.dayOfYear(new Temporal.PlainDateTime(1996, 12, 31, 5, 30, 13)) must return 366'
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/plain-date.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/plain-date.js
new file mode 100644
index 0000000000..59ae28381a
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/plain-date.js
@@ -0,0 +1,41 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.dayofyear
+description: >
+ Temporal.Calendar.prototype.dayOfYear will take PlainDate object and
+ return the day of year.
+info: |
+ 5. Return 𝔽(! ToISODayOfYear(temporalDate.[[ISOYear]], temporalDate.[[ISOMonth]], temporalDate.[[ISODay]])).
+features: [Temporal]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+let d = new Temporal.PlainDate(1970, 1, 1);
+assert.sameValue(cal.dayOfYear(d), 1, 'cal.dayOfYear(new Temporal.PlainDate(1970, 1, 1)) must return 1');
+d = new Temporal.PlainDate(2000, 1, 1);
+assert.sameValue(cal.dayOfYear(d), 1, 'cal.dayOfYear(new Temporal.PlainDate(2000, 1, 1)) must return 1');
+
+d = new Temporal.PlainDate(2021, 1, 15);
+assert.sameValue(cal.dayOfYear(d), 15, 'cal.dayOfYear(new Temporal.PlainDate(2021, 1, 15)) must return 15');
+
+d = new Temporal.PlainDate(2020, 2, 15);
+assert.sameValue(cal.dayOfYear(d), 46, 'cal.dayOfYear(new Temporal.PlainDate(2020, 2, 15)) must return 46');
+
+d = new Temporal.PlainDate(2020, 3, 15);
+assert.sameValue(cal.dayOfYear(d), 75, 'cal.dayOfYear(new Temporal.PlainDate(2020, 3, 15)) must return 75');
+
+d = new Temporal.PlainDate(2000, 3, 15);
+assert.sameValue(cal.dayOfYear(d), 75, 'cal.dayOfYear(new Temporal.PlainDate(2000, 3, 15)) must return 75');
+
+d = new Temporal.PlainDate(2001, 3, 15);
+assert.sameValue(cal.dayOfYear(d), 74, 'cal.dayOfYear(new Temporal.PlainDate(2001, 3, 15)) must return 74');
+
+d = new Temporal.PlainDate(2000, 12, 31);
+assert.sameValue(cal.dayOfYear(d), 366, 'cal.dayOfYear(new Temporal.PlainDate(2000, 12, 31)) must return 366');
+
+d = new Temporal.PlainDate(2001, 12, 31);
+assert.sameValue(cal.dayOfYear(d), 365, 'cal.dayOfYear(new Temporal.PlainDate(2001, 12, 31)) must return 365');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/prop-desc.js
new file mode 100644
index 0000000000..36da5f9f97
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/prop-desc.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofyear
+description: The "dayOfYear" property of Temporal.Calendar.prototype
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+assert.sameValue(
+ typeof Temporal.Calendar.prototype.dayOfYear,
+ "function",
+ "`typeof Calendar.prototype.dayOfYear` is `function`"
+);
+
+verifyProperty(Temporal.Calendar.prototype, "dayOfYear", {
+ writable: true,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/shell.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/shell.js
new file mode 100644
index 0000000000..eda1477282
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/shell.js
@@ -0,0 +1,24 @@
+// GENERATED, DO NOT EDIT
+// file: isConstructor.js
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: |
+ Test if a given function is a constructor function.
+defines: [isConstructor]
+features: [Reflect.construct]
+---*/
+
+function isConstructor(f) {
+ if (typeof f !== "function") {
+ throw new Test262Error("isConstructor invoked with a non-function value");
+ }
+
+ try {
+ Reflect.construct(function(){}, [], f);
+ } catch (e) {
+ return false;
+ }
+ return true;
+}
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/string.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/string.js
new file mode 100644
index 0000000000..1faed72a64
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/string.js
@@ -0,0 +1,37 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.dayofyear
+description: >
+ Temporal.Calendar.prototype.dayOfYear will take ISO8601 string and
+ return the day of year.
+info: |
+ 4. Let temporalDate be ? ToTemporalDate(temporalDateLike).
+ 5. Return 𝔽(! ToISODayOfYear(temporalDate.[[ISOYear]], temporalDate.[[ISOMonth]], temporalDate.[[ISODay]])).
+features: [Temporal]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+assert.sameValue(
+ cal.dayOfYear("2019-01-18"),
+ 18,
+ 'cal.dayOfYear("2019-01-18") must return 18'
+);
+assert.sameValue(
+ cal.dayOfYear("2020-02-18"),
+ 49,
+ 'cal.dayOfYear("2020-02-18") must return 49'
+);
+assert.sameValue(
+ cal.dayOfYear("2019-12-31"),
+ 365,
+ 'cal.dayOfYear("2019-12-31") must return 365'
+);
+assert.sameValue(
+ cal.dayOfYear("2000-12-31"),
+ 366,
+ 'cal.dayOfYear("2000-12-31") must return 366'
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/throw-range-error-ToTemporalDate.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/throw-range-error-ToTemporalDate.js
new file mode 100644
index 0000000000..52080766e5
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/throw-range-error-ToTemporalDate.js
@@ -0,0 +1,18 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.dayOfYear
+description: >
+ Temporal.Calendar.prototype.dayOfYear throws RangeError on
+ ToTemporalDate when temporalDateLike is invalid string.
+info: |
+ 4. Let temporalDate be ? ToTemporalDate(temporalDateLike).
+features: [Temporal, arrow-function]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+assert.throws(RangeError, () => cal.dayOfYear("invalid string"),
+ 'cal.dayOfYear("invalid string") throws a RangeError exception');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/year-zero.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/year-zero.js
new file mode 100644
index 0000000000..27c08f65f3
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/dayOfYear/year-zero.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofyear
+description: Negative zero, as an extended year, is rejected
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ "-000000-10-31",
+ "-000000-10-31T00:45",
+ "-000000-10-31T00:45+01:00",
+ "-000000-10-31T00:45+00:00[UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.dayOfYear(arg),
+ "reject minus zero as extended year"
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-builtin-calendar-no-array-iteration.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-builtin-calendar-no-array-iteration.js
new file mode 100644
index 0000000000..319534ca4f
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-builtin-calendar-no-array-iteration.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: >
+ Calling the method with a property bag argument with a builtin calendar causes
+ no observable array iteration when getting the calendar fields.
+features: [Temporal]
+---*/
+
+const arrayPrototypeSymbolIteratorOriginal = Array.prototype[Symbol.iterator];
+Array.prototype[Symbol.iterator] = function arrayIterator() {
+ throw new Test262Error("Array should not be iterated");
+}
+
+const instance = new Temporal.Calendar("iso8601");
+const arg = { year: 2000, month: 5, day: 2, calendar: "iso8601" };
+instance.daysInMonth(arg);
+
+Array.prototype[Symbol.iterator] = arrayPrototypeSymbolIteratorOriginal;
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-calendar-datefromfields-called-with-null-prototype-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-calendar-datefromfields-called-with-null-prototype-fields.js
new file mode 100644
index 0000000000..1198405424
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-calendar-datefromfields-called-with-null-prototype-fields.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: >
+ Calendar.dateFromFields method is called with a null-prototype fields object
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarCheckFieldsPrototypePollution();
+const instance = new Temporal.Calendar("iso8601");
+const arg = { year: 2000, month: 5, day: 2, calendar };
+instance.daysInMonth(arg);
+assert.sameValue(calendar.dateFromFieldsCallCount, 1, "dateFromFields should be called on the property bag's calendar");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-constructor-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-constructor-in-calendar-fields.js
new file mode 100644
index 0000000000..50db14415b
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-constructor-in-calendar-fields.js
@@ -0,0 +1,17 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: If a calendar's fields() method returns a field named 'constructor', PrepareTemporalFields should throw a RangeError.
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarWithExtraFields(['constructor']);
+const arg = {year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar};
+const instance = new Temporal.Calendar("iso8601");
+
+assert.throws(RangeError, () => instance.daysInMonth(arg));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-duplicate-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-duplicate-calendar-fields.js
new file mode 100644
index 0000000000..d183b4ee69
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-duplicate-calendar-fields.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: If a calendar's fields() method returns duplicate field names, PrepareTemporalFields should throw a RangeError.
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+for (const extra_fields of [['foo', 'foo'], ['day'], ['month'], ['monthCode'], ['year']]) {
+ const calendar = TemporalHelpers.calendarWithExtraFields(extra_fields);
+ const arg = { year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar };
+ const instance = new Temporal.Calendar("iso8601");
+
+ assert.throws(RangeError, () => instance.daysInMonth(arg));
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-leap-second.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-leap-second.js
new file mode 100644
index 0000000000..30e56f42b2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-leap-second.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: Leap second is a valid ISO string for PlainDate
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+let arg = "2016-12-31T23:59:60";
+const result1 = instance.daysInMonth(arg);
+assert.sameValue(
+ result1,
+ 31,
+ "leap second is a valid ISO string for PlainDate"
+);
+
+arg = { year: 2016, month: 12, day: 31, hour: 23, minute: 59, second: 60 };
+const result2 = instance.daysInMonth(arg);
+assert.sameValue(
+ result2,
+ 31,
+ "second: 60 is ignored in property bag for PlainDate"
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-number.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-number.js
new file mode 100644
index 0000000000..e2f40427c9
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-number.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: A number cannot be used in place of a Temporal.PlainDate
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const numbers = [
+ 1,
+ 19761118,
+ -19761118,
+ 1234567890,
+];
+
+for (const arg of numbers) {
+ assert.throws(
+ TypeError,
+ () => instance.daysInMonth(arg),
+ 'Numbers cannot be used in place of an ISO string for PlainDate'
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-propertybag-calendar-case-insensitive.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-propertybag-calendar-case-insensitive.js
new file mode 100644
index 0000000000..bcda4dbf08
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-propertybag-calendar-case-insensitive.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: The calendar name is case-insensitive
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const calendar = "IsO8601";
+
+const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+const result = instance.daysInMonth(arg);
+assert.sameValue(result, 30, "Calendar is case-insensitive");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-propertybag-calendar-leap-second.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-propertybag-calendar-leap-second.js
new file mode 100644
index 0000000000..bd6efd827b
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-propertybag-calendar-leap-second.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: Leap second is a valid ISO string for a calendar in a property bag
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const calendar = "2016-12-31T23:59:60";
+
+const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+const result = instance.daysInMonth(arg);
+assert.sameValue(
+ result,
+ 30,
+ "leap second is a valid ISO string for calendar"
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-propertybag-calendar-number.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-propertybag-calendar-number.js
new file mode 100644
index 0000000000..4a2e0fe015
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-propertybag-calendar-number.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: A number as calendar in a property bag is not accepted
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const numbers = [
+ 1,
+ 19970327,
+ -19970327,
+ 1234567890,
+];
+
+for (const calendar of numbers) {
+ const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+ assert.throws(
+ TypeError,
+ () => instance.daysInMonth(arg),
+ "Numbers cannot be used as a calendar"
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-propertybag-calendar-string.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-propertybag-calendar-string.js
new file mode 100644
index 0000000000..8f207d8388
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-propertybag-calendar-string.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: A calendar ID is valid input for Calendar
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const calendar = "iso8601";
+
+const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+const result = instance.daysInMonth(arg);
+assert.sameValue(result, 30, `Calendar created from string "${calendar}"`);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-propertybag-calendar-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-propertybag-calendar-wrong-type.js
new file mode 100644
index 0000000000..beb74d902f
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-propertybag-calendar-wrong-type.js
@@ -0,0 +1,46 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: >
+ Appropriate error thrown when a calendar property from a property bag cannot
+ be converted to a calendar object or string
+features: [BigInt, Symbol, Temporal]
+---*/
+
+const timeZone = new Temporal.TimeZone("UTC");
+const instance = new Temporal.Calendar("iso8601");
+
+const primitiveTests = [
+ [null, "null"],
+ [true, "boolean"],
+ ["", "empty string"],
+ [1, "number that doesn't convert to a valid ISO string"],
+ [1n, "bigint"],
+];
+
+for (const [calendar, description] of primitiveTests) {
+ const arg = { year: 2019, monthCode: "M11", day: 1, calendar };
+ assert.throws(
+ typeof calendar === 'string' ? RangeError : TypeError,
+ () => instance.daysInMonth(arg),
+ `${description} does not convert to a valid ISO string`
+ );
+}
+
+const typeErrorTests = [
+ [Symbol(), "symbol"],
+ [{}, "plain object that doesn't implement the protocol"],
+ [new Temporal.TimeZone("UTC"), "time zone instance"],
+ [Temporal.Calendar, "Temporal.Calendar, object"],
+ [Temporal.Calendar.prototype, "Temporal.Calendar.prototype, object"], // fails brand check in dateFromFields()
+];
+
+for (const [calendar, description] of typeErrorTests) {
+ const arg = { year: 2019, monthCode: "M11", day: 1, calendar };
+ assert.throws(TypeError, () => instance.daysInMonth(arg), `${description} is not a valid property bag and does not convert to a string`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-propertybag-calendar-year-zero.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-propertybag-calendar-year-zero.js
new file mode 100644
index 0000000000..8a6f651473
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-propertybag-calendar-year-zero.js
@@ -0,0 +1,27 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: Negative zero, as an extended year, is rejected
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ "-000000-10-31",
+ "-000000-10-31T17:45",
+ "-000000-10-31T17:45Z",
+ "-000000-10-31T17:45+01:00",
+ "-000000-10-31T17:45+00:00[UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.daysInMonth(arg),
+ "reject minus zero as extended year"
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-proto-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-proto-in-calendar-fields.js
new file mode 100644
index 0000000000..54de92486e
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-proto-in-calendar-fields.js
@@ -0,0 +1,17 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: If a calendar's fields() method returns a field named '__proto__', PrepareTemporalFields should throw a RangeError.
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarWithExtraFields(['__proto__']);
+const arg = {year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar};
+const instance = new Temporal.Calendar("iso8601");
+
+assert.throws(RangeError, () => instance.daysInMonth(arg));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-calendar-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-calendar-annotation.js
new file mode 100644
index 0000000000..4a0ed3ba9f
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-calendar-annotation.js
@@ -0,0 +1,33 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: Various forms of calendar annotation; critical flag has no effect
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02[u-ca=iso8601]", "without time or time zone"],
+ ["2000-05-02[UTC][u-ca=iso8601]", "with time zone and no time"],
+ ["2000-05-02T15:23[u-ca=iso8601]", "without time zone"],
+ ["2000-05-02T15:23[UTC][u-ca=iso8601]", "with time zone"],
+ ["2000-05-02T15:23[!u-ca=iso8601]", "with ! and no time zone"],
+ ["2000-05-02T15:23[UTC][!u-ca=iso8601]", "with ! and time zone"],
+ ["2000-05-02T15:23[u-ca=iso8601][u-ca=discord]", "second annotation ignored"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.daysInMonth(arg);
+
+ assert.sameValue(
+ result,
+ 31,
+ `calendar annotation (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-critical-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-critical-unknown-annotation.js
new file mode 100644
index 0000000000..fd0f58ec15
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-critical-unknown-annotation.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: Unknown annotations with critical flag are rejected
+features: [Temporal]
+---*/
+
+const invalidStrings = [
+ "1970-01-01[!foo=bar]",
+ "1970-01-01T00:00[!foo=bar]",
+ "1970-01-01T00:00[UTC][!foo=bar]",
+ "1970-01-01T00:00[u-ca=iso8601][!foo=bar]",
+ "1970-01-01T00:00[UTC][!foo=bar][u-ca=iso8601]",
+ "1970-01-01T00:00[foo=bar][!_foo-bar0=Dont-Ignore-This-99999999999]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.daysInMonth(arg),
+ `reject unknown annotation with critical flag: ${arg}`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-date-with-utc-offset.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-date-with-utc-offset.js
new file mode 100644
index 0000000000..8a7a746a83
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-date-with-utc-offset.js
@@ -0,0 +1,48 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: UTC offset not valid with format that does not include a time
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const validStrings = [
+ "2000-05-02T00+00:00",
+ "2000-05-02T00+00:00[UTC]",
+ "2000-05-02T00+00:00[!UTC]",
+ "2000-05-02T00-02:30[America/St_Johns]",
+];
+
+for (const arg of validStrings) {
+ const result = instance.daysInMonth(arg);
+
+ assert.sameValue(
+ result,
+ 31,
+ `"${arg}" is a valid UTC offset with time for PlainDate`
+ );
+}
+
+const invalidStrings = [
+ "2022-09-15Z",
+ "2022-09-15Z[UTC]",
+ "2022-09-15Z[Europe/Vienna]",
+ "2022-09-15+00:00",
+ "2022-09-15+00:00[UTC]",
+ "2022-09-15-02:30",
+ "2022-09-15-02:30[America/St_Johns]",
+];
+
+for (const arg of invalidStrings) {
+ assert.throws(
+ RangeError,
+ () => instance.daysInMonth(arg),
+ `"${arg}" UTC offset without time is not valid for PlainDate`
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-invalid.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-invalid.js
new file mode 100644
index 0000000000..5d4b66354e
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-invalid.js
@@ -0,0 +1,64 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: >
+ RangeError thrown if an invalid ISO string (or syntactically valid ISO string
+ that is not supported) is used as a PlainDate
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ // invalid ISO strings:
+ "",
+ "invalid iso8601",
+ "2020-01-00",
+ "2020-01-32",
+ "2020-02-30",
+ "2021-02-29",
+ "2020-00-01",
+ "2020-13-01",
+ "2020-01-01T",
+ "2020-01-01T25:00:00",
+ "2020-01-01T01:60:00",
+ "2020-01-01T01:60:61",
+ "2020-01-01junk",
+ "2020-01-01T00:00:00junk",
+ "2020-01-01T00:00:00+00:00junk",
+ "2020-01-01T00:00:00+00:00[UTC]junk",
+ "2020-01-01T00:00:00+00:00[UTC][u-ca=iso8601]junk",
+ "02020-01-01",
+ "2020-001-01",
+ "2020-01-001",
+ "2020-01-01T001",
+ "2020-01-01T01:001",
+ "2020-01-01T01:01:001",
+ // valid, but forms not supported in Temporal:
+ "2020-W01-1",
+ "2020-001",
+ "+0002020-01-01",
+ // valid, but this calendar must not exist:
+ "2020-01-01[u-ca=notexist]",
+ // may be valid in other contexts, but insufficient information for PlainDate:
+ "2020-01",
+ "+002020-01",
+ "01-01",
+ "2020-W01",
+ "P1Y",
+ "-P12Y",
+ // valid, but outside the supported range:
+ "-999999-01-01",
+ "+999999-01-01",
+];
+const instance = new Temporal.Calendar("iso8601");
+for (const arg of invalidStrings) {
+ assert.throws(
+ RangeError,
+ () => instance.daysInMonth(arg),
+ `"${arg}" should not be a valid ISO string for a PlainDate`
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-multiple-calendar.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-multiple-calendar.js
new file mode 100644
index 0000000000..a6b940ebf0
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-multiple-calendar.js
@@ -0,0 +1,32 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: >
+ More than one calendar annotation is not syntactical if any have the criical
+ flag
+features: [Temporal]
+---*/
+
+const invalidStrings = [
+ "1970-01-01[u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01[!u-ca=iso8601][u-ca=iso8601]",
+ "1970-01-01[UTC][u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01[u-ca=iso8601][foo=bar][!u-ca=iso8601]",
+ "1970-01-01T00:00[u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01T00:00[!u-ca=iso8601][u-ca=iso8601]",
+ "1970-01-01T00:00[UTC][u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01T00:00[u-ca=iso8601][foo=bar][!u-ca=iso8601]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.daysInMonth(arg),
+ `reject more than one calendar annotation if any critical: ${arg}`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-multiple-time-zone.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-multiple-time-zone.js
new file mode 100644
index 0000000000..5087ca2fe5
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-multiple-time-zone.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: More than one time zone annotation is not syntactical
+features: [Temporal]
+---*/
+
+const invalidStrings = [
+ "1970-01-01[UTC][UTC]",
+ "1970-01-01T00:00[UTC][UTC]",
+ "1970-01-01T00:00[!UTC][UTC]",
+ "1970-01-01T00:00[UTC][!UTC]",
+ "1970-01-01T00:00[UTC][u-ca=iso8601][UTC]",
+ "1970-01-01T00:00[UTC][foo=bar][UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.daysInMonth(arg),
+ `reject more than one time zone annotation: ${arg}`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-time-separators.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-time-separators.js
new file mode 100644
index 0000000000..049dd56d85
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-time-separators.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: Time separator in string argument can vary
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02T15:23", "uppercase T"],
+ ["2000-05-02t15:23", "lowercase T"],
+ ["2000-05-02 15:23", "space between date and time"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.daysInMonth(arg);
+
+ assert.sameValue(
+ result,
+ 31,
+ `variant time separators (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-time-zone-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-time-zone-annotation.js
new file mode 100644
index 0000000000..7432b240c0
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-time-zone-annotation.js
@@ -0,0 +1,38 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: Various forms of time zone annotation; critical flag has no effect
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02[Asia/Kolkata]", "named, with no time"],
+ ["2000-05-02[!Europe/Vienna]", "named, with ! and no time"],
+ ["2000-05-02[+00:00]", "numeric, with no time"],
+ ["2000-05-02[!-02:30]", "numeric, with ! and no time"],
+ ["2000-05-02T15:23[America/Sao_Paulo]", "named, with no offset"],
+ ["2000-05-02T15:23[!Asia/Tokyo]", "named, with ! and no offset"],
+ ["2000-05-02T15:23[-02:30]", "numeric, with no offset"],
+ ["2000-05-02T15:23[!+00:00]", "numeric, with ! and no offset"],
+ ["2000-05-02T15:23+00:00[America/New_York]", "named, with offset"],
+ ["2000-05-02T15:23+00:00[!UTC]", "named, with offset and !"],
+ ["2000-05-02T15:23+00:00[+01:00]", "numeric, with offset"],
+ ["2000-05-02T15:23+00:00[!-08:00]", "numeric, with offset and !"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.daysInMonth(arg);
+
+ assert.sameValue(
+ result,
+ 31,
+ `time zone annotation (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-unknown-annotation.js
new file mode 100644
index 0000000000..7b9329b45f
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-unknown-annotation.js
@@ -0,0 +1,32 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: Various forms of unknown annotation
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02[foo=bar]", "without time"],
+ ["2000-05-02T15:23[foo=bar]", "alone"],
+ ["2000-05-02T15:23[UTC][foo=bar]", "with time zone"],
+ ["2000-05-02T15:23[u-ca=iso8601][foo=bar]", "with calendar"],
+ ["2000-05-02T15:23[UTC][foo=bar][u-ca=iso8601]", "with time zone and calendar"],
+ ["2000-05-02T15:23[foo=bar][_foo-bar0=Ignore-This-999999999999]", "with another unknown annotation"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.daysInMonth(arg);
+
+ assert.sameValue(
+ result,
+ 31,
+ `unknown annotation (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-with-utc-designator.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-with-utc-designator.js
new file mode 100644
index 0000000000..2f221212ea
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-with-utc-designator.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: RangeError thrown if a string with UTC designator is used as a PlainDate
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ "2019-10-01T09:00:00Z",
+ "2019-10-01T09:00:00Z[UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.daysInMonth(arg),
+ "String with UTC designator should not be valid as a PlainDate"
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-wrong-type.js
new file mode 100644
index 0000000000..074c5479f8
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-wrong-type.js
@@ -0,0 +1,43 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: >
+ Appropriate error thrown when argument cannot be converted to a valid string
+ or property bag for PlainDate
+features: [BigInt, Symbol, Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const primitiveTests = [
+ [undefined, "undefined"],
+ [null, "null"],
+ [true, "boolean"],
+ ["", "empty string"],
+ [1, "number that doesn't convert to a valid ISO string"],
+ [1n, "bigint"],
+];
+
+for (const [arg, description] of primitiveTests) {
+ assert.throws(
+ typeof arg === 'string' ? RangeError : TypeError,
+ () => instance.daysInMonth(arg),
+ `${description} does not convert to a valid ISO string`
+ );
+}
+
+const typeErrorTests = [
+ [Symbol(), "symbol"],
+ [{}, "plain object"],
+ [Temporal.PlainDate, "Temporal.PlainDate, object"],
+ [Temporal.PlainDate.prototype, "Temporal.PlainDate.prototype, object"],
+];
+
+for (const [arg, description] of typeErrorTests) {
+ assert.throws(TypeError, () => instance.daysInMonth(arg), `${description} is not a valid property bag and does not convert to a string`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-convert.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-convert.js
new file mode 100644
index 0000000000..4d826cd5b7
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-convert.js
@@ -0,0 +1,22 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: An exception from TimeZone#getOffsetNanosecondsFor() is propagated.
+features: [Temporal]
+---*/
+
+class TZ extends Temporal.TimeZone {
+ constructor() { super("UTC") }
+ getOffsetNanosecondsFor() { throw new Test262Error() }
+}
+
+const tz = new TZ();
+const arg = new Temporal.ZonedDateTime(0n, tz);
+const instance = new Temporal.Calendar("iso8601");
+
+assert.throws(Test262Error, () => instance.daysInMonth(arg));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-slots.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-slots.js
new file mode 100644
index 0000000000..3ca0d6e1d4
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-slots.js
@@ -0,0 +1,40 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: Getters are not called when converting a ZonedDateTime to a PlainDate.
+includes: [compareArray.js]
+features: [Temporal]
+---*/
+
+const actual = [];
+const prototypeDescrs = Object.getOwnPropertyDescriptors(Temporal.ZonedDateTime.prototype);
+const getters = ["year", "month", "monthCode", "day", "hour", "minute", "second", "millisecond", "microsecond", "nanosecond", "calendar"];
+
+for (const property of getters) {
+ Object.defineProperty(Temporal.ZonedDateTime.prototype, property, {
+ get() {
+ actual.push(`get ${property}`);
+ const value = prototypeDescrs[property].get.call(this);
+ return {
+ toString() {
+ actual.push(`toString ${property}`);
+ return value.toString();
+ },
+ valueOf() {
+ actual.push(`valueOf ${property}`);
+ return value;
+ },
+ };
+ },
+ });
+}
+
+const arg = new Temporal.ZonedDateTime(0n, "UTC");
+const instance = new Temporal.Calendar("iso8601");
+instance.daysInMonth(arg);
+assert.compareArray(actual, []);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js
new file mode 100644
index 0000000000..645308ec95
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: RangeError thrown if time zone reports an offset that is not an integer number of nanoseconds
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+[3600_000_000_000.5, NaN, -Infinity, Infinity].forEach((wrongOffset) => {
+ const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset);
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ assert.throws(RangeError, () => calendar.daysInMonth(datetime));
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js
new file mode 100644
index 0000000000..8ed7f33ff2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: TypeError thrown if timeZone.getOffsetNanosecondsFor is not callable
+features: [BigInt, Symbol, Temporal, arrow-function]
+---*/
+
+[undefined, null, true, Math.PI, 'string', Symbol('sym'), 42n, {}].forEach((notCallable) => {
+ const timeZone = new Temporal.TimeZone("UTC");
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ timeZone.getOffsetNanosecondsFor = notCallable;
+ assert.throws(
+ TypeError,
+ () => calendar.daysInMonth(datetime),
+ `Uncallable ${notCallable === null ? 'null' : typeof notCallable} getOffsetNanosecondsFor should throw TypeError`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js
new file mode 100644
index 0000000000..3ed66442c2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: RangeError thrown if time zone reports an offset that is out of range
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+[-86400_000_000_000, 86400_000_000_000].forEach((wrongOffset) => {
+ const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset);
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ assert.throws(RangeError, () => calendar.daysInMonth(datetime));
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js
new file mode 100644
index 0000000000..5c18bfdbcd
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: TypeError thrown if time zone reports an offset that is not a Number
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+[
+ undefined,
+ null,
+ true,
+ "+01:00",
+ Symbol(),
+ 3600_000_000_000n,
+ {},
+ { valueOf() { return 3600_000_000_000; } },
+].forEach((wrongOffset) => {
+ const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset);
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ assert.throws(TypeError, () => calendar.daysInMonth(datetime));
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/basic.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/basic.js
new file mode 100644
index 0000000000..85985cb146
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/basic.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: Basic tests for daysInMonth().
+features: [Temporal]
+---*/
+
+const iso = Temporal.Calendar.from("iso8601");
+const res = 30;
+assert.sameValue(iso.daysInMonth(Temporal.PlainDate.from("1994-11-05")), res, "PlainDate");
+assert.sameValue(iso.daysInMonth(Temporal.PlainDateTime.from("1994-11-05T08:15:30")), res, "PlainDateTime");
+assert.sameValue(iso.daysInMonth({ year: 1994, month: 11, day: 5 }), res, "property bag");
+assert.sameValue(iso.daysInMonth("1994-11-05"), res, "string");
+assert.throws(TypeError, () => iso.daysInMonth({ year: 2000 }), "property bag with missing properties");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/branding.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/branding.js
new file mode 100644
index 0000000000..0a08a13ba8
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/branding.js
@@ -0,0 +1,27 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: Throw a TypeError if the receiver is invalid
+features: [Symbol, Temporal]
+---*/
+
+const daysInMonth = Temporal.Calendar.prototype.daysInMonth;
+
+assert.sameValue(typeof daysInMonth, "function");
+
+const args = [new Temporal.PlainDate(2000, 1, 1)];
+
+assert.throws(TypeError, () => daysInMonth.apply(undefined, args), "undefined");
+assert.throws(TypeError, () => daysInMonth.apply(null, args), "null");
+assert.throws(TypeError, () => daysInMonth.apply(true, args), "true");
+assert.throws(TypeError, () => daysInMonth.apply("", args), "empty string");
+assert.throws(TypeError, () => daysInMonth.apply(Symbol(), args), "symbol");
+assert.throws(TypeError, () => daysInMonth.apply(1, args), "1");
+assert.throws(TypeError, () => daysInMonth.apply({}, args), "plain object");
+assert.throws(TypeError, () => daysInMonth.apply(Temporal.Calendar, args), "Temporal.Calendar");
+assert.throws(TypeError, () => daysInMonth.apply(Temporal.Calendar.prototype, args), "Temporal.Calendar.prototype");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/browser.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/browser.js
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/builtin.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/builtin.js
new file mode 100644
index 0000000000..55e16b81a4
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/builtin.js
@@ -0,0 +1,36 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: >
+ Tests that Temporal.Calendar.prototype.daysInMonth
+ meets the requirements for built-in objects defined by the
+ introduction of chapter 17 of the ECMAScript Language Specification.
+info: |
+ Built-in functions that are not constructors do not have a "prototype" property unless
+ otherwise specified in the description of a particular function.
+
+ Unless specified otherwise, a built-in object that is callable as a function is a built-in
+ function object with the characteristics described in 10.3. Unless specified otherwise, the
+ [[Extensible]] internal slot of a built-in object initially has the value true.
+
+ Unless otherwise specified every built-in function and every built-in constructor has the
+ Function prototype object [...] as the value of its [[Prototype]] internal slot.
+features: [Temporal]
+---*/
+
+assert.sameValue(Object.isExtensible(Temporal.Calendar.prototype.daysInMonth),
+ true, "Built-in objects must be extensible.");
+
+assert.sameValue(Object.prototype.toString.call(Temporal.Calendar.prototype.daysInMonth),
+ "[object Function]", "Object.prototype.toString");
+
+assert.sameValue(Object.getPrototypeOf(Temporal.Calendar.prototype.daysInMonth),
+ Function.prototype, "prototype");
+
+assert.sameValue(Temporal.Calendar.prototype.daysInMonth.hasOwnProperty("prototype"),
+ false, "prototype property");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/calendar-datefromfields-called-with-options-undefined.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/calendar-datefromfields-called-with-options-undefined.js
new file mode 100644
index 0000000000..30931996c1
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/calendar-datefromfields-called-with-options-undefined.js
@@ -0,0 +1,18 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: >
+ Calendar.dateFromFields method is called with undefined as the options value
+ when call originates internally
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions();
+calendar.daysInMonth({ year: 2000, month: 5, day: 3, calendar });
+assert.sameValue(calendar.dateFromFieldsCallCount, 1);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/calendar-fields-iterable.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/calendar-fields-iterable.js
new file mode 100644
index 0000000000..9ea5126443
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/calendar-fields-iterable.js
@@ -0,0 +1,35 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: Verify the result of calendar.fields() is treated correctly.
+info: |
+ sec-temporal.calendar.prototype.daysinmonth step 4.a:
+ a. Set _dateOrDateTime_ to ? ToTemporalDate(_dateOrDateTime_).
+ sec-temporal-totemporaldate step 2.c:
+ c. Let _fieldNames_ be ? CalendarFields(_calendar_, « *"day"*, *"month"*, *"monthCode"*, *"year"* »).
+ sec-temporal-calendarfields step 4:
+ 4. Let _result_ be ? IterableToListOfType(_fieldsArray_, « String »).
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const expected = [
+ "day",
+ "month",
+ "monthCode",
+ "year",
+];
+
+const calendar1 = TemporalHelpers.calendarFieldsIterable();
+const calendar2 = TemporalHelpers.calendarFieldsIterable();
+calendar1.daysInMonth({ year: 2000, month: 5, day: 2, calendar: calendar2 });
+
+assert.sameValue(calendar1.fieldsCallCount, 0, "fields() method not called");
+assert.sameValue(calendar2.fieldsCallCount, 1, "fields() method called once");
+assert.compareArray(calendar2.fieldsCalledWith[0], expected, "fields() method called with correct args");
+assert(calendar2.iteratorExhausted[0], "iterated through the whole iterable");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/calendar-temporal-object.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/calendar-temporal-object.js
new file mode 100644
index 0000000000..00bad9889f
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/calendar-temporal-object.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: Fast path for converting other Temporal objects to Temporal.Calendar by reading internal slots
+info: |
+ sec-temporal.calendar.prototype.daysinmonth step 4.a:
+ a. Set _dateOrDateTime_ to ? ToTemporalDate(_dateOrDateTime_).
+ sec-temporal-totemporaldate step 2.c:
+ c. Let _calendar_ be ? GetTemporalCalendarWithISODefault(_item_).
+ sec-temporal-gettemporalcalendarwithisodefault step 2:
+ 2. Return ? ToTemporalCalendarWithISODefault(_calendar_).
+ sec-temporal-totemporalcalendarwithisodefault step 2:
+ 3. Return ? ToTemporalCalendar(_temporalCalendarLike_).
+ sec-temporal-totemporalcalendar step 1.a:
+ a. If _temporalCalendarLike_ has an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]], [[InitializedTemporalMonthDay]], [[InitializedTemporalYearMonth]], or [[InitializedTemporalZonedDateTime]] internal slot, then
+ i. Return _temporalCalendarLike_.[[Calendar]].
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+TemporalHelpers.checkToTemporalCalendarFastPath((temporalObject) => {
+ const calendar = new Temporal.Calendar("iso8601");
+ calendar.daysInMonth({ year: 2000, month: 5, day: 2, calendar: temporalObject });
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/infinity-throws-rangeerror.js
new file mode 100644
index 0000000000..eb47f7d645
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/infinity-throws-rangeerror.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: Throws if any value in the property bag is Infinity or -Infinity
+esid: sec-temporal.calendar.prototype.daysinmonth
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+const base = { year: 2000, month: 5, day: 2 };
+
+[Infinity, -Infinity].forEach((inf) => {
+ ["year", "month", "day"].forEach((prop) => {
+ assert.throws(RangeError, () => instance.daysInMonth({ ...base, [prop]: inf }), `${prop} property cannot be ${inf}`);
+
+ const calls = [];
+ const obj = TemporalHelpers.toPrimitiveObserver(calls, inf, prop);
+ assert.throws(RangeError, () => instance.daysInMonth({ ...base, [prop]: obj }));
+ assert.compareArray(calls, [`get ${prop}.valueOf`, `call ${prop}.valueOf`], "it fails after fetching the primitive value");
+ });
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/length.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/length.js
new file mode 100644
index 0000000000..fe4acc1334
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/length.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2020 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: Temporal.Calendar.prototype.daysInMonth.length is 1
+info: |
+ Every built-in function object, including constructors, has a "length" property whose value is
+ an integer. Unless otherwise specified, this value is equal to the largest number of named
+ arguments shown in the subclause headings for the function description. Optional parameters
+ (which are indicated with brackets: [ ]) or rest parameters (which are shown using the form
+ «...name») are not included in the default argument count.
+
+ Unless otherwise specified, the "length" property of a built-in function object has the
+ attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+verifyProperty(Temporal.Calendar.prototype.daysInMonth, "length", {
+ value: 1,
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/name.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/name.js
new file mode 100644
index 0000000000..6d65a4c15a
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/name.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: Temporal.Calendar.prototype.daysInMonth.name is "daysInMonth".
+info: |
+ Every built-in function object, including constructors, that is not identified as an anonymous
+ function has a "name" property whose value is a String. Unless otherwise specified, this value
+ is the name that is given to the function in this specification.
+
+ Unless otherwise specified, the "name" property of a built-in function object, if it exists,
+ has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+verifyProperty(Temporal.Calendar.prototype.daysInMonth, "name", {
+ value: "daysInMonth",
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/not-a-constructor.js
new file mode 100644
index 0000000000..f7edc90848
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/not-a-constructor.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: >
+ Temporal.Calendar.prototype.daysInMonth does not implement [[Construct]], is not new-able
+info: |
+ Built-in function objects that are not identified as constructors do not implement the
+ [[Construct]] internal method unless otherwise specified in the description of a particular
+ function.
+includes: [isConstructor.js]
+features: [Reflect.construct, Temporal]
+---*/
+
+assert.throws(TypeError, () => {
+ new Temporal.Calendar.prototype.daysInMonth();
+}, "Calling as constructor");
+
+assert.sameValue(isConstructor(Temporal.Calendar.prototype.daysInMonth), false,
+ "isConstructor(Temporal.Calendar.prototype.daysInMonth)");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/plain-date-time.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/plain-date-time.js
new file mode 100644
index 0000000000..26e9a810fd
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/plain-date-time.js
@@ -0,0 +1,116 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: >
+ Temporal.Calendar.prototype.daysInMonth will take Temporal.PlainDateTime object
+ and return the number of days in that month.
+info: |
+ 4. If Type(temporalDateLike) is not Object or temporalDateLike does not have an [[InitializedTemporalDate]] or [[InitializedTemporalYearMonth]] internal slots, then
+ a. Set temporalDateLike to ? ToTemporalDate(temporalDateLike).
+ 5. Return 𝔽(! ISODaysInMonth(temporalDateLike.[[ISOYear]], temporalDateLike.[[ISOMonth]])).
+features: [Temporal]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+let dt = new Temporal.PlainDateTime(1997, 1, 23, 5, 30, 13);
+assert.sameValue(
+ cal.daysInMonth(dt),
+ 31,
+ 'cal.daysInMonth(new Temporal.PlainDateTime(1997, 1, 23, 5, 30, 13)) must return 31'
+);
+
+// leap year
+dt = new Temporal.PlainDateTime(1996, 2, 23, 5, 30, 13);
+assert.sameValue(
+ cal.daysInMonth(dt),
+ 29,
+ 'cal.daysInMonth(new Temporal.PlainDateTime(1996, 2, 23, 5, 30, 13)) must return 29'
+);
+dt = new Temporal.PlainDateTime(2000, 2, 23, 5, 30, 13);
+assert.sameValue(
+ cal.daysInMonth(dt),
+ 29,
+ 'cal.daysInMonth(new Temporal.PlainDateTime(2000, 2, 23, 5, 30, 13)) must return 29'
+);
+
+// non leap year
+dt = new Temporal.PlainDateTime(1997, 2, 23, 5, 30, 13);
+assert.sameValue(
+ cal.daysInMonth(dt),
+ 28,
+ 'cal.daysInMonth(new Temporal.PlainDateTime(1997, 2, 23, 5, 30, 13)) must return 28'
+);
+
+dt = new Temporal.PlainDateTime(1997, 3, 23, 5, 30, 13);
+assert.sameValue(
+ cal.daysInMonth(dt),
+ 31,
+ 'cal.daysInMonth(new Temporal.PlainDateTime(1997, 3, 23, 5, 30, 13)) must return 31'
+);
+
+dt = new Temporal.PlainDateTime(1997, 4, 23, 5, 30, 13);
+assert.sameValue(
+ cal.daysInMonth(dt),
+ 30,
+ 'cal.daysInMonth(new Temporal.PlainDateTime(1997, 4, 23, 5, 30, 13)) must return 30'
+);
+
+dt = new Temporal.PlainDateTime(1997, 5, 23, 5, 30, 13);
+assert.sameValue(
+ cal.daysInMonth(dt),
+ 31,
+ 'cal.daysInMonth(new Temporal.PlainDateTime(1997, 5, 23, 5, 30, 13)) must return 31'
+);
+
+dt = new Temporal.PlainDateTime(1997, 6, 23, 5, 30, 13);
+assert.sameValue(
+ cal.daysInMonth(dt),
+ 30,
+ 'cal.daysInMonth(new Temporal.PlainDateTime(1997, 6, 23, 5, 30, 13)) must return 30'
+);
+
+dt = new Temporal.PlainDateTime(1997, 7, 23, 5, 30, 13);
+assert.sameValue(
+ cal.daysInMonth(dt),
+ 31,
+ 'cal.daysInMonth(new Temporal.PlainDateTime(1997, 7, 23, 5, 30, 13)) must return 31'
+);
+
+dt = new Temporal.PlainDateTime(1997, 8, 23, 5, 30, 13);
+assert.sameValue(
+ cal.daysInMonth(dt),
+ 31,
+ 'cal.daysInMonth(new Temporal.PlainDateTime(1997, 8, 23, 5, 30, 13)) must return 31'
+);
+
+dt = new Temporal.PlainDateTime(1997, 9, 23, 5, 30, 13);
+assert.sameValue(
+ cal.daysInMonth(dt),
+ 30,
+ 'cal.daysInMonth(new Temporal.PlainDateTime(1997, 9, 23, 5, 30, 13)) must return 30'
+);
+
+dt = new Temporal.PlainDateTime(1997, 10, 23, 5, 30, 13);
+assert.sameValue(
+ cal.daysInMonth(dt),
+ 31,
+ 'cal.daysInMonth(new Temporal.PlainDateTime(1997, 10, 23, 5, 30, 13)) must return 31'
+);
+
+dt = new Temporal.PlainDateTime(1997, 11, 23, 5, 30, 13);
+assert.sameValue(
+ cal.daysInMonth(dt),
+ 30,
+ 'cal.daysInMonth(new Temporal.PlainDateTime(1997, 11, 23, 5, 30, 13)) must return 30'
+);
+
+dt = new Temporal.PlainDateTime(1997, 12, 23, 5, 30, 13);
+assert.sameValue(
+ cal.daysInMonth(dt),
+ 31,
+ 'cal.daysInMonth(new Temporal.PlainDateTime(1997, 12, 23, 5, 30, 13)) must return 31'
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/plain-date.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/plain-date.js
new file mode 100644
index 0000000000..edb6f55093
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/plain-date.js
@@ -0,0 +1,58 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: >
+ Temporal.Calendar.prototype.daysInMonth will take Temporal.PlainDate object
+ and return the number of days in that month.
+info: |
+ 5. Return 𝔽(! ISODaysInMonth(temporalDateLike.[[ISOYear]], temporalDateLike.[[ISOMonth]])).
+features: [Temporal]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+let d = new Temporal.PlainDate(2021, 1, 15);
+assert.sameValue(cal.daysInMonth(d), 31, 'cal.daysInMonth(new Temporal.PlainDate(2021, 1, 15)) must return 31');
+
+// non-leap year
+d = new Temporal.PlainDate(2021, 2, 15);
+assert.sameValue(cal.daysInMonth(d), 28, 'cal.daysInMonth(new Temporal.PlainDate(2021, 2, 15)) must return 28');
+
+// leap year
+d = new Temporal.PlainDate(2020, 2, 15);
+assert.sameValue(cal.daysInMonth(d), 29, 'cal.daysInMonth(new Temporal.PlainDate(2020, 2, 15)) must return 29');
+d = new Temporal.PlainDate(2000, 2, 15);
+assert.sameValue(cal.daysInMonth(d), 29, 'cal.daysInMonth(new Temporal.PlainDate(2000, 2, 15)) must return 29');
+
+d = new Temporal.PlainDate(2021, 3, 15);
+assert.sameValue(cal.daysInMonth(d), 31, 'cal.daysInMonth(new Temporal.PlainDate(2021, 3, 15)) must return 31');
+
+d = new Temporal.PlainDate(2021, 4, 15);
+assert.sameValue(cal.daysInMonth(d), 30, 'cal.daysInMonth(new Temporal.PlainDate(2021, 4, 15)) must return 30');
+
+d = new Temporal.PlainDate(2021, 5, 15);
+assert.sameValue(cal.daysInMonth(d), 31, 'cal.daysInMonth(new Temporal.PlainDate(2021, 5, 15)) must return 31');
+
+d = new Temporal.PlainDate(2021, 6, 15);
+assert.sameValue(cal.daysInMonth(d), 30, 'cal.daysInMonth(new Temporal.PlainDate(2021, 6, 15)) must return 30');
+
+d = new Temporal.PlainDate(2021, 7, 15);
+assert.sameValue(cal.daysInMonth(d), 31, 'cal.daysInMonth(new Temporal.PlainDate(2021, 7, 15)) must return 31');
+
+d = new Temporal.PlainDate(2021, 8, 15);
+assert.sameValue(cal.daysInMonth(d), 31, 'cal.daysInMonth(new Temporal.PlainDate(2021, 8, 15)) must return 31');
+
+d = new Temporal.PlainDate(2021, 9, 15);
+assert.sameValue(cal.daysInMonth(d), 30, 'cal.daysInMonth(new Temporal.PlainDate(2021, 9, 15)) must return 30');
+
+d = new Temporal.PlainDate(2021, 10, 15);
+assert.sameValue(cal.daysInMonth(d), 31, 'cal.daysInMonth(new Temporal.PlainDate(2021, 10, 15)) must return 31');
+
+d = new Temporal.PlainDate(2021, 11, 15);
+assert.sameValue(cal.daysInMonth(d), 30, 'cal.daysInMonth(new Temporal.PlainDate(2021, 11, 15)) must return 30');
+
+d = new Temporal.PlainDate(2021, 12, 15);
+assert.sameValue(cal.daysInMonth(d), 31, 'cal.daysInMonth(new Temporal.PlainDate(2021, 12, 15)) must return 31');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/prop-desc.js
new file mode 100644
index 0000000000..d2f45ed5ca
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/prop-desc.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: The "daysInMonth" property of Temporal.Calendar.prototype
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+assert.sameValue(
+ typeof Temporal.Calendar.prototype.daysInMonth,
+ "function",
+ "`typeof Calendar.prototype.daysInMonth` is `function`"
+);
+
+verifyProperty(Temporal.Calendar.prototype, "daysInMonth", {
+ writable: true,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/shell.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/shell.js
new file mode 100644
index 0000000000..eda1477282
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/shell.js
@@ -0,0 +1,24 @@
+// GENERATED, DO NOT EDIT
+// file: isConstructor.js
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: |
+ Test if a given function is a constructor function.
+defines: [isConstructor]
+features: [Reflect.construct]
+---*/
+
+function isConstructor(f) {
+ if (typeof f !== "function") {
+ throw new Test262Error("isConstructor invoked with a non-function value");
+ }
+
+ try {
+ Reflect.construct(function(){}, [], f);
+ } catch (e) {
+ return false;
+ }
+ return true;
+}
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/string.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/string.js
new file mode 100644
index 0000000000..0f236a1622
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/string.js
@@ -0,0 +1,35 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: >
+ Temporal.Calendar.prototype.daysInMonth will take ISO8601 string
+ and return the number of days in that month.
+info: |
+ 4. If Type(temporalDateLike) is not Object or temporalDateLike does not have
+ an [[InitializedTemporalDate]] or [[InitializedTemporalYearMonth]] internal
+ slots, then
+ a. Set temporalDateLike to ? ToTemporalDate(temporalDateLike).
+ 5. Return 𝔽(! ISODaysInMonth(temporalDateLike.[[ISOYear]], temporalDateLike.[[ISOMonth]])).
+features: [Temporal]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+assert.sameValue(cal.daysInMonth("2019-01-18"), 31, 'cal.daysInMonth("2019-01-18") must return 31');
+// leap year
+assert.sameValue(cal.daysInMonth("2020-02-18"), 29, 'cal.daysInMonth("2020-02-18") must return 29');
+// non leap
+assert.sameValue(cal.daysInMonth("2019-02-18"), 28, 'cal.daysInMonth("2019-02-18") must return 28');
+assert.sameValue(cal.daysInMonth("2019-03-18"), 31, 'cal.daysInMonth("2019-03-18") must return 31');
+assert.sameValue(cal.daysInMonth("2019-04-18"), 30, 'cal.daysInMonth("2019-04-18") must return 30');
+assert.sameValue(cal.daysInMonth("2019-05-18"), 31, 'cal.daysInMonth("2019-05-18") must return 31');
+assert.sameValue(cal.daysInMonth("2019-06-18"), 30, 'cal.daysInMonth("2019-06-18") must return 30');
+assert.sameValue(cal.daysInMonth("2019-07-18"), 31, 'cal.daysInMonth("2019-07-18") must return 31');
+assert.sameValue(cal.daysInMonth("2019-08-18"), 31, 'cal.daysInMonth("2019-08-18") must return 31');
+assert.sameValue(cal.daysInMonth("2019-09-18"), 30, 'cal.daysInMonth("2019-09-18") must return 30');
+assert.sameValue(cal.daysInMonth("2019-10-18"), 31, 'cal.daysInMonth("2019-10-18") must return 31');
+assert.sameValue(cal.daysInMonth("2019-11-18"), 30, 'cal.daysInMonth("2019-11-18") must return 30');
+assert.sameValue(cal.daysInMonth("2019-12-18"), 31, 'cal.daysInMonth("2019-12-18") must return 31');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/throw-range-error-ToTemporalDate.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/throw-range-error-ToTemporalDate.js
new file mode 100644
index 0000000000..6571d37f2d
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/throw-range-error-ToTemporalDate.js
@@ -0,0 +1,21 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.daysInMonth
+description: >
+ Temporal.Calendar.prototype.daysInMonth throws RangeError on
+ ToTemporalDate when temporalDateLike is invalid string.
+info: |
+ 4. If Type(temporalDateLike) is not Object or temporalDateLike does not have
+ an [[InitializedTemporalDate]] or [[InitializedTemporalYearMonth]] internal
+ slots, then
+ a. Set temporalDateLike to ? ToTemporalDate(temporalDateLike).
+features: [Temporal, arrow-function]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+assert.throws(RangeError, () => cal.daysInMonth("invalid string"),
+ 'cal.daysInMonth("invalid string") throws a RangeError exception');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/year-zero.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/year-zero.js
new file mode 100644
index 0000000000..7974098376
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/year-zero.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: Negative zero, as an extended year, is rejected
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ "-000000-10-31",
+ "-000000-10-31T00:45",
+ "-000000-10-31T00:45+01:00",
+ "-000000-10-31T00:45+00:00[UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.daysInMonth(arg),
+ "reject minus zero as extended year"
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-builtin-calendar-no-array-iteration.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-builtin-calendar-no-array-iteration.js
new file mode 100644
index 0000000000..110aed2bed
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-builtin-calendar-no-array-iteration.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinweek
+description: >
+ Calling the method with a property bag argument with a builtin calendar causes
+ no observable array iteration when getting the calendar fields.
+features: [Temporal]
+---*/
+
+const arrayPrototypeSymbolIteratorOriginal = Array.prototype[Symbol.iterator];
+Array.prototype[Symbol.iterator] = function arrayIterator() {
+ throw new Test262Error("Array should not be iterated");
+}
+
+const instance = new Temporal.Calendar("iso8601");
+const arg = { year: 2000, month: 5, day: 2, calendar: "iso8601" };
+instance.daysInWeek(arg);
+
+Array.prototype[Symbol.iterator] = arrayPrototypeSymbolIteratorOriginal;
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-calendar-datefromfields-called-with-null-prototype-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-calendar-datefromfields-called-with-null-prototype-fields.js
new file mode 100644
index 0000000000..3db254da68
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-calendar-datefromfields-called-with-null-prototype-fields.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinweek
+description: >
+ Calendar.dateFromFields method is called with a null-prototype fields object
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarCheckFieldsPrototypePollution();
+const instance = new Temporal.Calendar("iso8601");
+const arg = { year: 2000, month: 5, day: 2, calendar };
+instance.daysInWeek(arg);
+assert.sameValue(calendar.dateFromFieldsCallCount, 1, "dateFromFields should be called on the property bag's calendar");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-constructor-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-constructor-in-calendar-fields.js
new file mode 100644
index 0000000000..8952ae023f
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-constructor-in-calendar-fields.js
@@ -0,0 +1,17 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.daysinweek
+description: If a calendar's fields() method returns a field named 'constructor', PrepareTemporalFields should throw a RangeError.
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarWithExtraFields(['constructor']);
+const arg = {year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar};
+const instance = new Temporal.Calendar("iso8601");
+
+assert.throws(RangeError, () => instance.daysInWeek(arg));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-duplicate-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-duplicate-calendar-fields.js
new file mode 100644
index 0000000000..c36efdc0a9
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-duplicate-calendar-fields.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.daysinweek
+description: If a calendar's fields() method returns duplicate field names, PrepareTemporalFields should throw a RangeError.
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+for (const extra_fields of [['foo', 'foo'], ['day'], ['month'], ['monthCode'], ['year']]) {
+ const calendar = TemporalHelpers.calendarWithExtraFields(extra_fields);
+ const arg = { year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar };
+ const instance = new Temporal.Calendar("iso8601");
+
+ assert.throws(RangeError, () => instance.daysInWeek(arg));
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-leap-second.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-leap-second.js
new file mode 100644
index 0000000000..aa15290d2f
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-leap-second.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinweek
+description: Leap second is a valid ISO string for PlainDate
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+let arg = "2016-12-31T23:59:60";
+const result1 = instance.daysInWeek(arg);
+assert.sameValue(
+ result1,
+ 7,
+ "leap second is a valid ISO string for PlainDate"
+);
+
+arg = { year: 2016, month: 12, day: 31, hour: 23, minute: 59, second: 60 };
+const result2 = instance.daysInWeek(arg);
+assert.sameValue(
+ result2,
+ 7,
+ "second: 60 is ignored in property bag for PlainDate"
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-number.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-number.js
new file mode 100644
index 0000000000..a279f5c8c2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-number.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinweek
+description: A number cannot be used in place of a Temporal.PlainDate
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const numbers = [
+ 1,
+ 19761118,
+ -19761118,
+ 1234567890,
+];
+
+for (const arg of numbers) {
+ assert.throws(
+ TypeError,
+ () => instance.daysInWeek(arg),
+ 'Numbers cannot be used in place of an ISO string for PlainDate'
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-propertybag-calendar-case-insensitive.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-propertybag-calendar-case-insensitive.js
new file mode 100644
index 0000000000..08a615e309
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-propertybag-calendar-case-insensitive.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinweek
+description: The calendar name is case-insensitive
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const calendar = "IsO8601";
+
+const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+const result = instance.daysInWeek(arg);
+assert.sameValue(result, 7, "Calendar is case-insensitive");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-propertybag-calendar-leap-second.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-propertybag-calendar-leap-second.js
new file mode 100644
index 0000000000..0a2b0806f9
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-propertybag-calendar-leap-second.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinweek
+description: Leap second is a valid ISO string for a calendar in a property bag
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const calendar = "2016-12-31T23:59:60";
+
+const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+const result = instance.daysInWeek(arg);
+assert.sameValue(
+ result,
+ 7,
+ "leap second is a valid ISO string for calendar"
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-propertybag-calendar-number.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-propertybag-calendar-number.js
new file mode 100644
index 0000000000..f4f77d8c2e
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-propertybag-calendar-number.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinweek
+description: A number as calendar in a property bag is not accepted
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const numbers = [
+ 1,
+ 19970327,
+ -19970327,
+ 1234567890,
+];
+
+for (const calendar of numbers) {
+ const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+ assert.throws(
+ TypeError,
+ () => instance.daysInWeek(arg),
+ "Numbers cannot be used as a calendar"
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-propertybag-calendar-string.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-propertybag-calendar-string.js
new file mode 100644
index 0000000000..556f29d81f
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-propertybag-calendar-string.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinweek
+description: A calendar ID is valid input for Calendar
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const calendar = "iso8601";
+
+const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+const result = instance.daysInWeek(arg);
+assert.sameValue(result, 7, `Calendar created from string "${calendar}"`);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-propertybag-calendar-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-propertybag-calendar-wrong-type.js
new file mode 100644
index 0000000000..11394edbb6
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-propertybag-calendar-wrong-type.js
@@ -0,0 +1,46 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinweek
+description: >
+ Appropriate error thrown when a calendar property from a property bag cannot
+ be converted to a calendar object or string
+features: [BigInt, Symbol, Temporal]
+---*/
+
+const timeZone = new Temporal.TimeZone("UTC");
+const instance = new Temporal.Calendar("iso8601");
+
+const primitiveTests = [
+ [null, "null"],
+ [true, "boolean"],
+ ["", "empty string"],
+ [1, "number that doesn't convert to a valid ISO string"],
+ [1n, "bigint"],
+];
+
+for (const [calendar, description] of primitiveTests) {
+ const arg = { year: 2019, monthCode: "M11", day: 1, calendar };
+ assert.throws(
+ typeof calendar === 'string' ? RangeError : TypeError,
+ () => instance.daysInWeek(arg),
+ `${description} does not convert to a valid ISO string`
+ );
+}
+
+const typeErrorTests = [
+ [Symbol(), "symbol"],
+ [{}, "plain object that doesn't implement the protocol"],
+ [new Temporal.TimeZone("UTC"), "time zone instance"],
+ [Temporal.Calendar, "Temporal.Calendar, object"],
+ [Temporal.Calendar.prototype, "Temporal.Calendar.prototype, object"], // fails brand check in dateFromFields()
+];
+
+for (const [calendar, description] of typeErrorTests) {
+ const arg = { year: 2019, monthCode: "M11", day: 1, calendar };
+ assert.throws(TypeError, () => instance.daysInWeek(arg), `${description} is not a valid property bag and does not convert to a string`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-propertybag-calendar-year-zero.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-propertybag-calendar-year-zero.js
new file mode 100644
index 0000000000..7d8395c074
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-propertybag-calendar-year-zero.js
@@ -0,0 +1,27 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinweek
+description: Negative zero, as an extended year, is rejected
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ "-000000-10-31",
+ "-000000-10-31T17:45",
+ "-000000-10-31T17:45Z",
+ "-000000-10-31T17:45+01:00",
+ "-000000-10-31T17:45+00:00[UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.daysInWeek(arg),
+ "reject minus zero as extended year"
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-proto-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-proto-in-calendar-fields.js
new file mode 100644
index 0000000000..cda32b22e9
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-proto-in-calendar-fields.js
@@ -0,0 +1,17 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.daysinweek
+description: If a calendar's fields() method returns a field named '__proto__', PrepareTemporalFields should throw a RangeError.
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarWithExtraFields(['__proto__']);
+const arg = {year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar};
+const instance = new Temporal.Calendar("iso8601");
+
+assert.throws(RangeError, () => instance.daysInWeek(arg));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-string-calendar-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-string-calendar-annotation.js
new file mode 100644
index 0000000000..25f5900218
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-string-calendar-annotation.js
@@ -0,0 +1,33 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinweek
+description: Various forms of calendar annotation; critical flag has no effect
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02[u-ca=iso8601]", "without time or time zone"],
+ ["2000-05-02[UTC][u-ca=iso8601]", "with time zone and no time"],
+ ["2000-05-02T15:23[u-ca=iso8601]", "without time zone"],
+ ["2000-05-02T15:23[UTC][u-ca=iso8601]", "with time zone"],
+ ["2000-05-02T15:23[!u-ca=iso8601]", "with ! and no time zone"],
+ ["2000-05-02T15:23[UTC][!u-ca=iso8601]", "with ! and time zone"],
+ ["2000-05-02T15:23[u-ca=iso8601][u-ca=discord]", "second annotation ignored"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.daysInWeek(arg);
+
+ assert.sameValue(
+ result,
+ 7,
+ `calendar annotation (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-string-critical-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-string-critical-unknown-annotation.js
new file mode 100644
index 0000000000..54755595a0
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-string-critical-unknown-annotation.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinweek
+description: Unknown annotations with critical flag are rejected
+features: [Temporal]
+---*/
+
+const invalidStrings = [
+ "1970-01-01[!foo=bar]",
+ "1970-01-01T00:00[!foo=bar]",
+ "1970-01-01T00:00[UTC][!foo=bar]",
+ "1970-01-01T00:00[u-ca=iso8601][!foo=bar]",
+ "1970-01-01T00:00[UTC][!foo=bar][u-ca=iso8601]",
+ "1970-01-01T00:00[foo=bar][!_foo-bar0=Dont-Ignore-This-99999999999]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.daysInWeek(arg),
+ `reject unknown annotation with critical flag: ${arg}`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-string-date-with-utc-offset.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-string-date-with-utc-offset.js
new file mode 100644
index 0000000000..74ece3cf77
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-string-date-with-utc-offset.js
@@ -0,0 +1,48 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinweek
+description: UTC offset not valid with format that does not include a time
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const validStrings = [
+ "2000-05-02T00+00:00",
+ "2000-05-02T00+00:00[UTC]",
+ "2000-05-02T00+00:00[!UTC]",
+ "2000-05-02T00-02:30[America/St_Johns]",
+];
+
+for (const arg of validStrings) {
+ const result = instance.daysInWeek(arg);
+
+ assert.sameValue(
+ result,
+ 7,
+ `"${arg}" is a valid UTC offset with time for PlainDate`
+ );
+}
+
+const invalidStrings = [
+ "2022-09-15Z",
+ "2022-09-15Z[UTC]",
+ "2022-09-15Z[Europe/Vienna]",
+ "2022-09-15+00:00",
+ "2022-09-15+00:00[UTC]",
+ "2022-09-15-02:30",
+ "2022-09-15-02:30[America/St_Johns]",
+];
+
+for (const arg of invalidStrings) {
+ assert.throws(
+ RangeError,
+ () => instance.daysInWeek(arg),
+ `"${arg}" UTC offset without time is not valid for PlainDate`
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-string-invalid.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-string-invalid.js
new file mode 100644
index 0000000000..c748c767a7
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-string-invalid.js
@@ -0,0 +1,64 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinweek
+description: >
+ RangeError thrown if an invalid ISO string (or syntactically valid ISO string
+ that is not supported) is used as a PlainDate
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ // invalid ISO strings:
+ "",
+ "invalid iso8601",
+ "2020-01-00",
+ "2020-01-32",
+ "2020-02-30",
+ "2021-02-29",
+ "2020-00-01",
+ "2020-13-01",
+ "2020-01-01T",
+ "2020-01-01T25:00:00",
+ "2020-01-01T01:60:00",
+ "2020-01-01T01:60:61",
+ "2020-01-01junk",
+ "2020-01-01T00:00:00junk",
+ "2020-01-01T00:00:00+00:00junk",
+ "2020-01-01T00:00:00+00:00[UTC]junk",
+ "2020-01-01T00:00:00+00:00[UTC][u-ca=iso8601]junk",
+ "02020-01-01",
+ "2020-001-01",
+ "2020-01-001",
+ "2020-01-01T001",
+ "2020-01-01T01:001",
+ "2020-01-01T01:01:001",
+ // valid, but forms not supported in Temporal:
+ "2020-W01-1",
+ "2020-001",
+ "+0002020-01-01",
+ // valid, but this calendar must not exist:
+ "2020-01-01[u-ca=notexist]",
+ // may be valid in other contexts, but insufficient information for PlainDate:
+ "2020-01",
+ "+002020-01",
+ "01-01",
+ "2020-W01",
+ "P1Y",
+ "-P12Y",
+ // valid, but outside the supported range:
+ "-999999-01-01",
+ "+999999-01-01",
+];
+const instance = new Temporal.Calendar("iso8601");
+for (const arg of invalidStrings) {
+ assert.throws(
+ RangeError,
+ () => instance.daysInWeek(arg),
+ `"${arg}" should not be a valid ISO string for a PlainDate`
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-string-multiple-calendar.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-string-multiple-calendar.js
new file mode 100644
index 0000000000..57ba7d4c4a
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-string-multiple-calendar.js
@@ -0,0 +1,32 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinweek
+description: >
+ More than one calendar annotation is not syntactical if any have the criical
+ flag
+features: [Temporal]
+---*/
+
+const invalidStrings = [
+ "1970-01-01[u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01[!u-ca=iso8601][u-ca=iso8601]",
+ "1970-01-01[UTC][u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01[u-ca=iso8601][foo=bar][!u-ca=iso8601]",
+ "1970-01-01T00:00[u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01T00:00[!u-ca=iso8601][u-ca=iso8601]",
+ "1970-01-01T00:00[UTC][u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01T00:00[u-ca=iso8601][foo=bar][!u-ca=iso8601]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.daysInWeek(arg),
+ `reject more than one calendar annotation if any critical: ${arg}`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-string-multiple-time-zone.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-string-multiple-time-zone.js
new file mode 100644
index 0000000000..fc99e1a45a
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-string-multiple-time-zone.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinweek
+description: More than one time zone annotation is not syntactical
+features: [Temporal]
+---*/
+
+const invalidStrings = [
+ "1970-01-01[UTC][UTC]",
+ "1970-01-01T00:00[UTC][UTC]",
+ "1970-01-01T00:00[!UTC][UTC]",
+ "1970-01-01T00:00[UTC][!UTC]",
+ "1970-01-01T00:00[UTC][u-ca=iso8601][UTC]",
+ "1970-01-01T00:00[UTC][foo=bar][UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.daysInWeek(arg),
+ `reject more than one time zone annotation: ${arg}`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-string-time-separators.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-string-time-separators.js
new file mode 100644
index 0000000000..1059a26053
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-string-time-separators.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinweek
+description: Time separator in string argument can vary
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02T15:23", "uppercase T"],
+ ["2000-05-02t15:23", "lowercase T"],
+ ["2000-05-02 15:23", "space between date and time"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.daysInWeek(arg);
+
+ assert.sameValue(
+ result,
+ 7,
+ `variant time separators (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-string-time-zone-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-string-time-zone-annotation.js
new file mode 100644
index 0000000000..9716308c3b
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-string-time-zone-annotation.js
@@ -0,0 +1,38 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinweek
+description: Various forms of time zone annotation; critical flag has no effect
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02[Asia/Kolkata]", "named, with no time"],
+ ["2000-05-02[!Europe/Vienna]", "named, with ! and no time"],
+ ["2000-05-02[+00:00]", "numeric, with no time"],
+ ["2000-05-02[!-02:30]", "numeric, with ! and no time"],
+ ["2000-05-02T15:23[America/Sao_Paulo]", "named, with no offset"],
+ ["2000-05-02T15:23[!Asia/Tokyo]", "named, with ! and no offset"],
+ ["2000-05-02T15:23[-02:30]", "numeric, with no offset"],
+ ["2000-05-02T15:23[!+00:00]", "numeric, with ! and no offset"],
+ ["2000-05-02T15:23+00:00[America/New_York]", "named, with offset"],
+ ["2000-05-02T15:23+00:00[!UTC]", "named, with offset and !"],
+ ["2000-05-02T15:23+00:00[+01:00]", "numeric, with offset"],
+ ["2000-05-02T15:23+00:00[!-08:00]", "numeric, with offset and !"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.daysInWeek(arg);
+
+ assert.sameValue(
+ result,
+ 7,
+ `time zone annotation (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-string-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-string-unknown-annotation.js
new file mode 100644
index 0000000000..d5ce3102a5
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-string-unknown-annotation.js
@@ -0,0 +1,32 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinweek
+description: Various forms of unknown annotation
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02[foo=bar]", "without time"],
+ ["2000-05-02T15:23[foo=bar]", "alone"],
+ ["2000-05-02T15:23[UTC][foo=bar]", "with time zone"],
+ ["2000-05-02T15:23[u-ca=iso8601][foo=bar]", "with calendar"],
+ ["2000-05-02T15:23[UTC][foo=bar][u-ca=iso8601]", "with time zone and calendar"],
+ ["2000-05-02T15:23[foo=bar][_foo-bar0=Ignore-This-999999999999]", "with another unknown annotation"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.daysInWeek(arg);
+
+ assert.sameValue(
+ result,
+ 7,
+ `unknown annotation (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-string-with-utc-designator.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-string-with-utc-designator.js
new file mode 100644
index 0000000000..5ba18b0ea1
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-string-with-utc-designator.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinweek
+description: RangeError thrown if a string with UTC designator is used as a PlainDate
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ "2019-10-01T09:00:00Z",
+ "2019-10-01T09:00:00Z[UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.daysInWeek(arg),
+ "String with UTC designator should not be valid as a PlainDate"
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-wrong-type.js
new file mode 100644
index 0000000000..449bb99be3
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-wrong-type.js
@@ -0,0 +1,43 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinweek
+description: >
+ Appropriate error thrown when argument cannot be converted to a valid string
+ or property bag for PlainDate
+features: [BigInt, Symbol, Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const primitiveTests = [
+ [undefined, "undefined"],
+ [null, "null"],
+ [true, "boolean"],
+ ["", "empty string"],
+ [1, "number that doesn't convert to a valid ISO string"],
+ [1n, "bigint"],
+];
+
+for (const [arg, description] of primitiveTests) {
+ assert.throws(
+ typeof arg === 'string' ? RangeError : TypeError,
+ () => instance.daysInWeek(arg),
+ `${description} does not convert to a valid ISO string`
+ );
+}
+
+const typeErrorTests = [
+ [Symbol(), "symbol"],
+ [{}, "plain object"],
+ [Temporal.PlainDate, "Temporal.PlainDate, object"],
+ [Temporal.PlainDate.prototype, "Temporal.PlainDate.prototype, object"],
+];
+
+for (const [arg, description] of typeErrorTests) {
+ assert.throws(TypeError, () => instance.daysInWeek(arg), `${description} is not a valid property bag and does not convert to a string`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-zoneddatetime-convert.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-zoneddatetime-convert.js
new file mode 100644
index 0000000000..941c35db81
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-zoneddatetime-convert.js
@@ -0,0 +1,22 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinweek
+description: An exception from TimeZone#getOffsetNanosecondsFor() is propagated.
+features: [Temporal]
+---*/
+
+class TZ extends Temporal.TimeZone {
+ constructor() { super("UTC") }
+ getOffsetNanosecondsFor() { throw new Test262Error() }
+}
+
+const tz = new TZ();
+const arg = new Temporal.ZonedDateTime(0n, tz);
+const instance = new Temporal.Calendar("iso8601");
+
+assert.throws(Test262Error, () => instance.daysInWeek(arg));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-zoneddatetime-slots.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-zoneddatetime-slots.js
new file mode 100644
index 0000000000..60a3547c9a
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-zoneddatetime-slots.js
@@ -0,0 +1,40 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinweek
+description: Getters are not called when converting a ZonedDateTime to a PlainDate.
+includes: [compareArray.js]
+features: [Temporal]
+---*/
+
+const actual = [];
+const prototypeDescrs = Object.getOwnPropertyDescriptors(Temporal.ZonedDateTime.prototype);
+const getters = ["year", "month", "monthCode", "day", "hour", "minute", "second", "millisecond", "microsecond", "nanosecond", "calendar"];
+
+for (const property of getters) {
+ Object.defineProperty(Temporal.ZonedDateTime.prototype, property, {
+ get() {
+ actual.push(`get ${property}`);
+ const value = prototypeDescrs[property].get.call(this);
+ return {
+ toString() {
+ actual.push(`toString ${property}`);
+ return value.toString();
+ },
+ valueOf() {
+ actual.push(`valueOf ${property}`);
+ return value;
+ },
+ };
+ },
+ });
+}
+
+const arg = new Temporal.ZonedDateTime(0n, "UTC");
+const instance = new Temporal.Calendar("iso8601");
+instance.daysInWeek(arg);
+assert.compareArray(actual, []);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js
new file mode 100644
index 0000000000..6145e1b1f3
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinweek
+description: RangeError thrown if time zone reports an offset that is not an integer number of nanoseconds
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+[3600_000_000_000.5, NaN, -Infinity, Infinity].forEach((wrongOffset) => {
+ const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset);
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ assert.throws(RangeError, () => calendar.daysInWeek(datetime));
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js
new file mode 100644
index 0000000000..10c6de0f88
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinweek
+description: TypeError thrown if timeZone.getOffsetNanosecondsFor is not callable
+features: [BigInt, Symbol, Temporal, arrow-function]
+---*/
+
+[undefined, null, true, Math.PI, 'string', Symbol('sym'), 42n, {}].forEach((notCallable) => {
+ const timeZone = new Temporal.TimeZone("UTC");
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ timeZone.getOffsetNanosecondsFor = notCallable;
+ assert.throws(
+ TypeError,
+ () => calendar.daysInWeek(datetime),
+ `Uncallable ${notCallable === null ? 'null' : typeof notCallable} getOffsetNanosecondsFor should throw TypeError`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js
new file mode 100644
index 0000000000..a2700dd325
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinweek
+description: RangeError thrown if time zone reports an offset that is out of range
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+[-86400_000_000_000, 86400_000_000_000].forEach((wrongOffset) => {
+ const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset);
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ assert.throws(RangeError, () => calendar.daysInWeek(datetime));
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js
new file mode 100644
index 0000000000..575f44a56f
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinweek
+description: TypeError thrown if time zone reports an offset that is not a Number
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+[
+ undefined,
+ null,
+ true,
+ "+01:00",
+ Symbol(),
+ 3600_000_000_000n,
+ {},
+ { valueOf() { return 3600_000_000_000; } },
+].forEach((wrongOffset) => {
+ const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset);
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ assert.throws(TypeError, () => calendar.daysInWeek(datetime));
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/basic.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/basic.js
new file mode 100644
index 0000000000..bc08c6bcd8
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/basic.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinweek
+description: Basic tests for daysInWeek().
+features: [Temporal]
+---*/
+
+const iso = Temporal.Calendar.from("iso8601");
+const res = 7;
+assert.sameValue(iso.daysInWeek(Temporal.PlainDate.from("1994-11-05")), res, "PlainDate");
+assert.sameValue(iso.daysInWeek(Temporal.PlainDateTime.from("1994-11-05T08:15:30")), res, "PlainDateTime");
+assert.sameValue(iso.daysInWeek({ year: 1994, month: 11, day: 5 }), res, "property bag");
+assert.sameValue(iso.daysInWeek("1994-11-05"), res, "string");
+assert.throws(TypeError, () => iso.daysInWeek({ year: 2000 }), "property bag with missing properties");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/branding.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/branding.js
new file mode 100644
index 0000000000..6772299fda
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/branding.js
@@ -0,0 +1,27 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinweek
+description: Throw a TypeError if the receiver is invalid
+features: [Symbol, Temporal]
+---*/
+
+const daysInWeek = Temporal.Calendar.prototype.daysInWeek;
+
+assert.sameValue(typeof daysInWeek, "function");
+
+const args = [new Temporal.PlainDate(2000, 1, 1)];
+
+assert.throws(TypeError, () => daysInWeek.apply(undefined, args), "undefined");
+assert.throws(TypeError, () => daysInWeek.apply(null, args), "null");
+assert.throws(TypeError, () => daysInWeek.apply(true, args), "true");
+assert.throws(TypeError, () => daysInWeek.apply("", args), "empty string");
+assert.throws(TypeError, () => daysInWeek.apply(Symbol(), args), "symbol");
+assert.throws(TypeError, () => daysInWeek.apply(1, args), "1");
+assert.throws(TypeError, () => daysInWeek.apply({}, args), "plain object");
+assert.throws(TypeError, () => daysInWeek.apply(Temporal.Calendar, args), "Temporal.Calendar");
+assert.throws(TypeError, () => daysInWeek.apply(Temporal.Calendar.prototype, args), "Temporal.Calendar.prototype");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/browser.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/browser.js
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/builtin.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/builtin.js
new file mode 100644
index 0000000000..d0cdf2e2ac
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/builtin.js
@@ -0,0 +1,36 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinweek
+description: >
+ Tests that Temporal.Calendar.prototype.daysInWeek
+ meets the requirements for built-in objects defined by the
+ introduction of chapter 17 of the ECMAScript Language Specification.
+info: |
+ Built-in functions that are not constructors do not have a "prototype" property unless
+ otherwise specified in the description of a particular function.
+
+ Unless specified otherwise, a built-in object that is callable as a function is a built-in
+ function object with the characteristics described in 10.3. Unless specified otherwise, the
+ [[Extensible]] internal slot of a built-in object initially has the value true.
+
+ Unless otherwise specified every built-in function and every built-in constructor has the
+ Function prototype object [...] as the value of its [[Prototype]] internal slot.
+features: [Temporal]
+---*/
+
+assert.sameValue(Object.isExtensible(Temporal.Calendar.prototype.daysInWeek),
+ true, "Built-in objects must be extensible.");
+
+assert.sameValue(Object.prototype.toString.call(Temporal.Calendar.prototype.daysInWeek),
+ "[object Function]", "Object.prototype.toString");
+
+assert.sameValue(Object.getPrototypeOf(Temporal.Calendar.prototype.daysInWeek),
+ Function.prototype, "prototype");
+
+assert.sameValue(Temporal.Calendar.prototype.daysInWeek.hasOwnProperty("prototype"),
+ false, "prototype property");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/calendar-datefromfields-called-with-options-undefined.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/calendar-datefromfields-called-with-options-undefined.js
new file mode 100644
index 0000000000..1c31202345
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/calendar-datefromfields-called-with-options-undefined.js
@@ -0,0 +1,18 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinweek
+description: >
+ Calendar.dateFromFields method is called with undefined as the options value
+ when call originates internally
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions();
+calendar.daysInWeek({ year: 2000, month: 5, day: 3, calendar });
+assert.sameValue(calendar.dateFromFieldsCallCount, 1);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/calendar-fields-iterable.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/calendar-fields-iterable.js
new file mode 100644
index 0000000000..5fe4eb09bd
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/calendar-fields-iterable.js
@@ -0,0 +1,35 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinweek
+description: Verify the result of calendar.fields() is treated correctly.
+info: |
+ sec-temporal.calendar.prototype.daysinweek step 4:
+ 4. Perform ? ToTemporalDate(_dateOrDateTime_).
+ sec-temporal-totemporaldate step 2.c:
+ c. Let _fieldNames_ be ? CalendarFields(_calendar_, « *"day"*, *"month"*, *"monthCode"*, *"year"* »).
+ sec-temporal-calendarfields step 4:
+ 4. Let _result_ be ? IterableToListOfType(_fieldsArray_, « String »).
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const expected = [
+ "day",
+ "month",
+ "monthCode",
+ "year",
+];
+
+const calendar1 = TemporalHelpers.calendarFieldsIterable();
+const calendar2 = TemporalHelpers.calendarFieldsIterable();
+calendar1.daysInWeek({ year: 2000, month: 5, day: 2, calendar: calendar2 });
+
+assert.sameValue(calendar1.fieldsCallCount, 0, "fields() method not called");
+assert.sameValue(calendar2.fieldsCallCount, 1, "fields() method called once");
+assert.compareArray(calendar2.fieldsCalledWith[0], expected, "fields() method called with correct args");
+assert(calendar2.iteratorExhausted[0], "iterated through the whole iterable");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/calendar-temporal-object.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/calendar-temporal-object.js
new file mode 100644
index 0000000000..98d7a71412
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/calendar-temporal-object.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinweek
+description: Fast path for converting other Temporal objects to Temporal.Calendar by reading internal slots
+info: |
+ sec-temporal.calendar.prototype.daysinweek step 4:
+ 4. Perform ? ToTemporalDate(_dateOrDateTime_).
+ sec-temporal-totemporaldate step 2.c:
+ c. Let _calendar_ be ? GetTemporalCalendarWithISODefault(_item_).
+ sec-temporal-gettemporalcalendarwithisodefault step 2:
+ 2. Return ? ToTemporalCalendarWithISODefault(_calendar_).
+ sec-temporal-totemporalcalendarwithisodefault step 2:
+ 3. Return ? ToTemporalCalendar(_temporalCalendarLike_).
+ sec-temporal-totemporalcalendar step 1.a:
+ a. If _temporalCalendarLike_ has an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]], [[InitializedTemporalMonthDay]], [[InitializedTemporalYearMonth]], or [[InitializedTemporalZonedDateTime]] internal slot, then
+ i. Return _temporalCalendarLike_.[[Calendar]].
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+TemporalHelpers.checkToTemporalCalendarFastPath((temporalObject) => {
+ const calendar = new Temporal.Calendar("iso8601");
+ calendar.daysInWeek({ year: 2000, month: 5, day: 2, calendar: temporalObject });
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/date-time.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/date-time.js
new file mode 100644
index 0000000000..7ab14c3ca8
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/date-time.js
@@ -0,0 +1,21 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.daysinweeks
+description: Temporal.Calendar.prototype.daysInWeek will take PlainDateTime and return 7.
+info: |
+ 4. Perform ? ToTemporalDate(temporalDateLike).
+ 5. Return 7𝔽.
+features: [Temporal]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+let dt = new Temporal.PlainDateTime(1997, 8, 23, 5, 30, 13);
+assert.sameValue(
+ cal.daysInWeek(dt),
+ 7,
+ 'cal.daysInWeek(new Temporal.PlainDateTime(1997, 8, 23, 5, 30, 13)) must return 7'
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/date.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/date.js
new file mode 100644
index 0000000000..62f2ff263a
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/date.js
@@ -0,0 +1,16 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.daysinweeks
+description: Temporal.Calendar.prototype.daysInWeek will take PlainDate and return 7.
+info: |
+ 5. Return 7𝔽.
+features: [Temporal]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+let d = new Temporal.PlainDate(2021, 7, 15);
+assert.sameValue(cal.daysInWeek(d), 7, 'cal.daysInWeek(new Temporal.PlainDate(2021, 7, 15)) must return 7');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/infinity-throws-rangeerror.js
new file mode 100644
index 0000000000..44cecb2e90
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/infinity-throws-rangeerror.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: Throws if any value in the property bag is Infinity or -Infinity
+esid: sec-temporal.calendar.prototype.daysinweek
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+const base = { year: 2000, month: 5, day: 2 };
+
+[Infinity, -Infinity].forEach((inf) => {
+ ["year", "month", "day"].forEach((prop) => {
+ assert.throws(RangeError, () => instance.daysInWeek({ ...base, [prop]: inf }), `${prop} property cannot be ${inf}`);
+
+ const calls = [];
+ const obj = TemporalHelpers.toPrimitiveObserver(calls, inf, prop);
+ assert.throws(RangeError, () => instance.daysInWeek({ ...base, [prop]: obj }));
+ assert.compareArray(calls, [`get ${prop}.valueOf`, `call ${prop}.valueOf`], "it fails after fetching the primitive value");
+ });
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/length.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/length.js
new file mode 100644
index 0000000000..b29774e9ff
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/length.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2020 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinweek
+description: Temporal.Calendar.prototype.daysInWeek.length is 1
+info: |
+ Every built-in function object, including constructors, has a "length" property whose value is
+ an integer. Unless otherwise specified, this value is equal to the largest number of named
+ arguments shown in the subclause headings for the function description. Optional parameters
+ (which are indicated with brackets: [ ]) or rest parameters (which are shown using the form
+ «...name») are not included in the default argument count.
+
+ Unless otherwise specified, the "length" property of a built-in function object has the
+ attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+verifyProperty(Temporal.Calendar.prototype.daysInWeek, "length", {
+ value: 1,
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/name.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/name.js
new file mode 100644
index 0000000000..59cfe96553
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/name.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinweek
+description: Temporal.Calendar.prototype.daysInWeek.name is "daysInWeek".
+info: |
+ Every built-in function object, including constructors, that is not identified as an anonymous
+ function has a "name" property whose value is a String. Unless otherwise specified, this value
+ is the name that is given to the function in this specification.
+
+ Unless otherwise specified, the "name" property of a built-in function object, if it exists,
+ has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+verifyProperty(Temporal.Calendar.prototype.daysInWeek, "name", {
+ value: "daysInWeek",
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/not-a-constructor.js
new file mode 100644
index 0000000000..3445a89301
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/not-a-constructor.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinweek
+description: >
+ Temporal.Calendar.prototype.daysInWeek does not implement [[Construct]], is not new-able
+info: |
+ Built-in function objects that are not identified as constructors do not implement the
+ [[Construct]] internal method unless otherwise specified in the description of a particular
+ function.
+includes: [isConstructor.js]
+features: [Reflect.construct, Temporal]
+---*/
+
+assert.throws(TypeError, () => {
+ new Temporal.Calendar.prototype.daysInWeek();
+}, "Calling as constructor");
+
+assert.sameValue(isConstructor(Temporal.Calendar.prototype.daysInWeek), false,
+ "isConstructor(Temporal.Calendar.prototype.daysInWeek)");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/prop-desc.js
new file mode 100644
index 0000000000..27bc5aca22
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/prop-desc.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinweek
+description: The "daysInWeek" property of Temporal.Calendar.prototype
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+assert.sameValue(
+ typeof Temporal.Calendar.prototype.daysInWeek,
+ "function",
+ "`typeof Calendar.prototype.daysInWeek` is `function`"
+);
+
+verifyProperty(Temporal.Calendar.prototype, "daysInWeek", {
+ writable: true,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/shell.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/shell.js
new file mode 100644
index 0000000000..eda1477282
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/shell.js
@@ -0,0 +1,24 @@
+// GENERATED, DO NOT EDIT
+// file: isConstructor.js
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: |
+ Test if a given function is a constructor function.
+defines: [isConstructor]
+features: [Reflect.construct]
+---*/
+
+function isConstructor(f) {
+ if (typeof f !== "function") {
+ throw new Test262Error("isConstructor invoked with a non-function value");
+ }
+
+ try {
+ Reflect.construct(function(){}, [], f);
+ } catch (e) {
+ return false;
+ }
+ return true;
+}
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/string.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/string.js
new file mode 100644
index 0000000000..b7ca1084a6
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/string.js
@@ -0,0 +1,17 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.daysinweeks
+description: >
+ Temporal.Calendar.prototype.daysInWeek will take valid ISO8601 string
+ and return 7.
+info: |
+ 4. Perform ? ToTemporalDate(temporalDateLike).
+ 5. Return 7𝔽.
+features: [Temporal]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+assert.sameValue(cal.daysInWeek("2019-03-18"), 7, 'cal.daysInWeek("2019-03-18") must return 7');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/throw-range-error-ToTemporalDate.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/throw-range-error-ToTemporalDate.js
new file mode 100644
index 0000000000..7bd6692848
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/throw-range-error-ToTemporalDate.js
@@ -0,0 +1,18 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.daysInWeek
+description: >
+ Temporal.Calendar.prototype.daysInWeek throws RangeError on
+ ToTemporalDate when temporalDateLike is invalid string.
+info: |
+ 4. Let temporalDate be ? ToTemporalDate(temporalDateLike).
+features: [Temporal, arrow-function]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+assert.throws(RangeError, () => cal.daysInWeek("invalid string"),
+ 'cal.daysInWeek("invalid string") throws a RangeError exception');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/year-zero.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/year-zero.js
new file mode 100644
index 0000000000..bdd058fe7a
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInWeek/year-zero.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinweek
+description: Negative zero, as an extended year, is rejected
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ "-000000-10-31",
+ "-000000-10-31T00:45",
+ "-000000-10-31T00:45+01:00",
+ "-000000-10-31T00:45+00:00[UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.daysInWeek(arg),
+ "reject minus zero as extended year"
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-builtin-calendar-no-array-iteration.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-builtin-calendar-no-array-iteration.js
new file mode 100644
index 0000000000..a1a9d56b40
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-builtin-calendar-no-array-iteration.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinyear
+description: >
+ Calling the method with a property bag argument with a builtin calendar causes
+ no observable array iteration when getting the calendar fields.
+features: [Temporal]
+---*/
+
+const arrayPrototypeSymbolIteratorOriginal = Array.prototype[Symbol.iterator];
+Array.prototype[Symbol.iterator] = function arrayIterator() {
+ throw new Test262Error("Array should not be iterated");
+}
+
+const instance = new Temporal.Calendar("iso8601");
+const arg = { year: 2000, month: 5, day: 2, calendar: "iso8601" };
+instance.daysInYear(arg);
+
+Array.prototype[Symbol.iterator] = arrayPrototypeSymbolIteratorOriginal;
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-calendar-datefromfields-called-with-null-prototype-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-calendar-datefromfields-called-with-null-prototype-fields.js
new file mode 100644
index 0000000000..b7d705dff3
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-calendar-datefromfields-called-with-null-prototype-fields.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinyear
+description: >
+ Calendar.dateFromFields method is called with a null-prototype fields object
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarCheckFieldsPrototypePollution();
+const instance = new Temporal.Calendar("iso8601");
+const arg = { year: 2000, month: 5, day: 2, calendar };
+instance.daysInYear(arg);
+assert.sameValue(calendar.dateFromFieldsCallCount, 1, "dateFromFields should be called on the property bag's calendar");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-constructor-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-constructor-in-calendar-fields.js
new file mode 100644
index 0000000000..f47b077c13
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-constructor-in-calendar-fields.js
@@ -0,0 +1,17 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.daysinyear
+description: If a calendar's fields() method returns a field named 'constructor', PrepareTemporalFields should throw a RangeError.
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarWithExtraFields(['constructor']);
+const arg = {year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar};
+const instance = new Temporal.Calendar("iso8601");
+
+assert.throws(RangeError, () => instance.daysInYear(arg));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-duplicate-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-duplicate-calendar-fields.js
new file mode 100644
index 0000000000..8600467296
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-duplicate-calendar-fields.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.daysinyear
+description: If a calendar's fields() method returns duplicate field names, PrepareTemporalFields should throw a RangeError.
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+for (const extra_fields of [['foo', 'foo'], ['day'], ['month'], ['monthCode'], ['year']]) {
+ const calendar = TemporalHelpers.calendarWithExtraFields(extra_fields);
+ const arg = { year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar };
+ const instance = new Temporal.Calendar("iso8601");
+
+ assert.throws(RangeError, () => instance.daysInYear(arg));
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-leap-second.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-leap-second.js
new file mode 100644
index 0000000000..7ea0a919f0
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-leap-second.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinyear
+description: Leap second is a valid ISO string for PlainDate
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+let arg = "2016-12-31T23:59:60";
+const result1 = instance.daysInYear(arg);
+assert.sameValue(
+ result1,
+ 366,
+ "leap second is a valid ISO string for PlainDate"
+);
+
+arg = { year: 2016, month: 12, day: 31, hour: 23, minute: 59, second: 60 };
+const result2 = instance.daysInYear(arg);
+assert.sameValue(
+ result2,
+ 366,
+ "second: 60 is ignored in property bag for PlainDate"
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-number.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-number.js
new file mode 100644
index 0000000000..a4192c3a91
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-number.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinyear
+description: A number cannot be used in place of a Temporal.PlainDate
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const numbers = [
+ 1,
+ 19761118,
+ -19761118,
+ 1234567890,
+];
+
+for (const arg of numbers) {
+ assert.throws(
+ TypeError,
+ () => instance.daysInYear(arg),
+ 'Numbers cannot be used in place of an ISO string for PlainDate'
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-propertybag-calendar-case-insensitive.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-propertybag-calendar-case-insensitive.js
new file mode 100644
index 0000000000..762b02f555
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-propertybag-calendar-case-insensitive.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinyear
+description: The calendar name is case-insensitive
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const calendar = "IsO8601";
+
+const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+const result = instance.daysInYear(arg);
+assert.sameValue(result, 366, "Calendar is case-insensitive");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-propertybag-calendar-leap-second.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-propertybag-calendar-leap-second.js
new file mode 100644
index 0000000000..a491924c6e
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-propertybag-calendar-leap-second.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinyear
+description: Leap second is a valid ISO string for a calendar in a property bag
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const calendar = "2016-12-31T23:59:60";
+
+const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+const result = instance.daysInYear(arg);
+assert.sameValue(
+ result,
+ 366,
+ "leap second is a valid ISO string for calendar"
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-propertybag-calendar-number.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-propertybag-calendar-number.js
new file mode 100644
index 0000000000..99a8086ff6
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-propertybag-calendar-number.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinyear
+description: A number as calendar in a property bag is not accepted
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const numbers = [
+ 1,
+ 19970327,
+ -19970327,
+ 1234567890,
+];
+
+for (const calendar of numbers) {
+ const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+ assert.throws(
+ TypeError,
+ () => instance.daysInYear(arg),
+ "Numbers cannot be used as a calendar"
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-propertybag-calendar-string.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-propertybag-calendar-string.js
new file mode 100644
index 0000000000..c1c2e5a742
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-propertybag-calendar-string.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinyear
+description: A calendar ID is valid input for Calendar
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const calendar = "iso8601";
+
+const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+const result = instance.daysInYear(arg);
+assert.sameValue(result, 366, `Calendar created from string "${calendar}"`);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-propertybag-calendar-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-propertybag-calendar-wrong-type.js
new file mode 100644
index 0000000000..b259e17cb9
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-propertybag-calendar-wrong-type.js
@@ -0,0 +1,46 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinyear
+description: >
+ Appropriate error thrown when a calendar property from a property bag cannot
+ be converted to a calendar object or string
+features: [BigInt, Symbol, Temporal]
+---*/
+
+const timeZone = new Temporal.TimeZone("UTC");
+const instance = new Temporal.Calendar("iso8601");
+
+const primitiveTests = [
+ [null, "null"],
+ [true, "boolean"],
+ ["", "empty string"],
+ [1, "number that doesn't convert to a valid ISO string"],
+ [1n, "bigint"],
+];
+
+for (const [calendar, description] of primitiveTests) {
+ const arg = { year: 2019, monthCode: "M11", day: 1, calendar };
+ assert.throws(
+ typeof calendar === 'string' ? RangeError : TypeError,
+ () => instance.daysInYear(arg),
+ `${description} does not convert to a valid ISO string`
+ );
+}
+
+const typeErrorTests = [
+ [Symbol(), "symbol"],
+ [{}, "plain object that doesn't implement the protocol"],
+ [new Temporal.TimeZone("UTC"), "time zone instance"],
+ [Temporal.Calendar, "Temporal.Calendar, object"],
+ [Temporal.Calendar.prototype, "Temporal.Calendar.prototype, object"], // fails brand check in dateFromFields()
+];
+
+for (const [calendar, description] of typeErrorTests) {
+ const arg = { year: 2019, monthCode: "M11", day: 1, calendar };
+ assert.throws(TypeError, () => instance.daysInYear(arg), `${description} is not a valid property bag and does not convert to a string`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-propertybag-calendar-year-zero.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-propertybag-calendar-year-zero.js
new file mode 100644
index 0000000000..18d81a4c17
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-propertybag-calendar-year-zero.js
@@ -0,0 +1,27 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinyear
+description: Negative zero, as an extended year, is rejected
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ "-000000-10-31",
+ "-000000-10-31T17:45",
+ "-000000-10-31T17:45Z",
+ "-000000-10-31T17:45+01:00",
+ "-000000-10-31T17:45+00:00[UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.daysInYear(arg),
+ "reject minus zero as extended year"
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-proto-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-proto-in-calendar-fields.js
new file mode 100644
index 0000000000..19af1a4da4
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-proto-in-calendar-fields.js
@@ -0,0 +1,17 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.daysinyear
+description: If a calendar's fields() method returns a field named '__proto__', PrepareTemporalFields should throw a RangeError.
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarWithExtraFields(['__proto__']);
+const arg = {year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar};
+const instance = new Temporal.Calendar("iso8601");
+
+assert.throws(RangeError, () => instance.daysInYear(arg));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-string-calendar-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-string-calendar-annotation.js
new file mode 100644
index 0000000000..bd1c76b3d1
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-string-calendar-annotation.js
@@ -0,0 +1,33 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinyear
+description: Various forms of calendar annotation; critical flag has no effect
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02[u-ca=iso8601]", "without time or time zone"],
+ ["2000-05-02[UTC][u-ca=iso8601]", "with time zone and no time"],
+ ["2000-05-02T15:23[u-ca=iso8601]", "without time zone"],
+ ["2000-05-02T15:23[UTC][u-ca=iso8601]", "with time zone"],
+ ["2000-05-02T15:23[!u-ca=iso8601]", "with ! and no time zone"],
+ ["2000-05-02T15:23[UTC][!u-ca=iso8601]", "with ! and time zone"],
+ ["2000-05-02T15:23[u-ca=iso8601][u-ca=discord]", "second annotation ignored"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.daysInYear(arg);
+
+ assert.sameValue(
+ result,
+ 366,
+ `calendar annotation (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-string-critical-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-string-critical-unknown-annotation.js
new file mode 100644
index 0000000000..4a4ce08fcf
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-string-critical-unknown-annotation.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinyear
+description: Unknown annotations with critical flag are rejected
+features: [Temporal]
+---*/
+
+const invalidStrings = [
+ "1970-01-01[!foo=bar]",
+ "1970-01-01T00:00[!foo=bar]",
+ "1970-01-01T00:00[UTC][!foo=bar]",
+ "1970-01-01T00:00[u-ca=iso8601][!foo=bar]",
+ "1970-01-01T00:00[UTC][!foo=bar][u-ca=iso8601]",
+ "1970-01-01T00:00[foo=bar][!_foo-bar0=Dont-Ignore-This-99999999999]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.daysInYear(arg),
+ `reject unknown annotation with critical flag: ${arg}`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-string-date-with-utc-offset.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-string-date-with-utc-offset.js
new file mode 100644
index 0000000000..b5cf28d12d
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-string-date-with-utc-offset.js
@@ -0,0 +1,48 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinyear
+description: UTC offset not valid with format that does not include a time
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const validStrings = [
+ "2000-05-02T00+00:00",
+ "2000-05-02T00+00:00[UTC]",
+ "2000-05-02T00+00:00[!UTC]",
+ "2000-05-02T00-02:30[America/St_Johns]",
+];
+
+for (const arg of validStrings) {
+ const result = instance.daysInYear(arg);
+
+ assert.sameValue(
+ result,
+ 366,
+ `"${arg}" is a valid UTC offset with time for PlainDate`
+ );
+}
+
+const invalidStrings = [
+ "2022-09-15Z",
+ "2022-09-15Z[UTC]",
+ "2022-09-15Z[Europe/Vienna]",
+ "2022-09-15+00:00",
+ "2022-09-15+00:00[UTC]",
+ "2022-09-15-02:30",
+ "2022-09-15-02:30[America/St_Johns]",
+];
+
+for (const arg of invalidStrings) {
+ assert.throws(
+ RangeError,
+ () => instance.daysInYear(arg),
+ `"${arg}" UTC offset without time is not valid for PlainDate`
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-string-invalid.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-string-invalid.js
new file mode 100644
index 0000000000..e26385f3ba
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-string-invalid.js
@@ -0,0 +1,64 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinyear
+description: >
+ RangeError thrown if an invalid ISO string (or syntactically valid ISO string
+ that is not supported) is used as a PlainDate
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ // invalid ISO strings:
+ "",
+ "invalid iso8601",
+ "2020-01-00",
+ "2020-01-32",
+ "2020-02-30",
+ "2021-02-29",
+ "2020-00-01",
+ "2020-13-01",
+ "2020-01-01T",
+ "2020-01-01T25:00:00",
+ "2020-01-01T01:60:00",
+ "2020-01-01T01:60:61",
+ "2020-01-01junk",
+ "2020-01-01T00:00:00junk",
+ "2020-01-01T00:00:00+00:00junk",
+ "2020-01-01T00:00:00+00:00[UTC]junk",
+ "2020-01-01T00:00:00+00:00[UTC][u-ca=iso8601]junk",
+ "02020-01-01",
+ "2020-001-01",
+ "2020-01-001",
+ "2020-01-01T001",
+ "2020-01-01T01:001",
+ "2020-01-01T01:01:001",
+ // valid, but forms not supported in Temporal:
+ "2020-W01-1",
+ "2020-001",
+ "+0002020-01-01",
+ // valid, but this calendar must not exist:
+ "2020-01-01[u-ca=notexist]",
+ // may be valid in other contexts, but insufficient information for PlainDate:
+ "2020-01",
+ "+002020-01",
+ "01-01",
+ "2020-W01",
+ "P1Y",
+ "-P12Y",
+ // valid, but outside the supported range:
+ "-999999-01-01",
+ "+999999-01-01",
+];
+const instance = new Temporal.Calendar("iso8601");
+for (const arg of invalidStrings) {
+ assert.throws(
+ RangeError,
+ () => instance.daysInYear(arg),
+ `"${arg}" should not be a valid ISO string for a PlainDate`
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-string-multiple-calendar.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-string-multiple-calendar.js
new file mode 100644
index 0000000000..5b8160db1f
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-string-multiple-calendar.js
@@ -0,0 +1,32 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinyear
+description: >
+ More than one calendar annotation is not syntactical if any have the criical
+ flag
+features: [Temporal]
+---*/
+
+const invalidStrings = [
+ "1970-01-01[u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01[!u-ca=iso8601][u-ca=iso8601]",
+ "1970-01-01[UTC][u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01[u-ca=iso8601][foo=bar][!u-ca=iso8601]",
+ "1970-01-01T00:00[u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01T00:00[!u-ca=iso8601][u-ca=iso8601]",
+ "1970-01-01T00:00[UTC][u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01T00:00[u-ca=iso8601][foo=bar][!u-ca=iso8601]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.daysInYear(arg),
+ `reject more than one calendar annotation if any critical: ${arg}`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-string-multiple-time-zone.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-string-multiple-time-zone.js
new file mode 100644
index 0000000000..37f4be64b6
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-string-multiple-time-zone.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinyear
+description: More than one time zone annotation is not syntactical
+features: [Temporal]
+---*/
+
+const invalidStrings = [
+ "1970-01-01[UTC][UTC]",
+ "1970-01-01T00:00[UTC][UTC]",
+ "1970-01-01T00:00[!UTC][UTC]",
+ "1970-01-01T00:00[UTC][!UTC]",
+ "1970-01-01T00:00[UTC][u-ca=iso8601][UTC]",
+ "1970-01-01T00:00[UTC][foo=bar][UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.daysInYear(arg),
+ `reject more than one time zone annotation: ${arg}`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-string-time-separators.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-string-time-separators.js
new file mode 100644
index 0000000000..d5b474c4ae
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-string-time-separators.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinyear
+description: Time separator in string argument can vary
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02T15:23", "uppercase T"],
+ ["2000-05-02t15:23", "lowercase T"],
+ ["2000-05-02 15:23", "space between date and time"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.daysInYear(arg);
+
+ assert.sameValue(
+ result,
+ 366,
+ `variant time separators (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-string-time-zone-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-string-time-zone-annotation.js
new file mode 100644
index 0000000000..be37b75348
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-string-time-zone-annotation.js
@@ -0,0 +1,38 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinyear
+description: Various forms of time zone annotation; critical flag has no effect
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02[Asia/Kolkata]", "named, with no time"],
+ ["2000-05-02[!Europe/Vienna]", "named, with ! and no time"],
+ ["2000-05-02[+00:00]", "numeric, with no time"],
+ ["2000-05-02[!-02:30]", "numeric, with ! and no time"],
+ ["2000-05-02T15:23[America/Sao_Paulo]", "named, with no offset"],
+ ["2000-05-02T15:23[!Asia/Tokyo]", "named, with ! and no offset"],
+ ["2000-05-02T15:23[-02:30]", "numeric, with no offset"],
+ ["2000-05-02T15:23[!+00:00]", "numeric, with ! and no offset"],
+ ["2000-05-02T15:23+00:00[America/New_York]", "named, with offset"],
+ ["2000-05-02T15:23+00:00[!UTC]", "named, with offset and !"],
+ ["2000-05-02T15:23+00:00[+01:00]", "numeric, with offset"],
+ ["2000-05-02T15:23+00:00[!-08:00]", "numeric, with offset and !"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.daysInYear(arg);
+
+ assert.sameValue(
+ result,
+ 366,
+ `time zone annotation (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-string-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-string-unknown-annotation.js
new file mode 100644
index 0000000000..56f5429ea1
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-string-unknown-annotation.js
@@ -0,0 +1,32 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinyear
+description: Various forms of unknown annotation
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02[foo=bar]", "without time"],
+ ["2000-05-02T15:23[foo=bar]", "alone"],
+ ["2000-05-02T15:23[UTC][foo=bar]", "with time zone"],
+ ["2000-05-02T15:23[u-ca=iso8601][foo=bar]", "with calendar"],
+ ["2000-05-02T15:23[UTC][foo=bar][u-ca=iso8601]", "with time zone and calendar"],
+ ["2000-05-02T15:23[foo=bar][_foo-bar0=Ignore-This-999999999999]", "with another unknown annotation"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.daysInYear(arg);
+
+ assert.sameValue(
+ result,
+ 366,
+ `unknown annotation (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-string-with-utc-designator.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-string-with-utc-designator.js
new file mode 100644
index 0000000000..0c09cafed0
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-string-with-utc-designator.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinyear
+description: RangeError thrown if a string with UTC designator is used as a PlainDate
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ "2019-10-01T09:00:00Z",
+ "2019-10-01T09:00:00Z[UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.daysInYear(arg),
+ "String with UTC designator should not be valid as a PlainDate"
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-wrong-type.js
new file mode 100644
index 0000000000..d74e334fb7
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-wrong-type.js
@@ -0,0 +1,43 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinyear
+description: >
+ Appropriate error thrown when argument cannot be converted to a valid string
+ or property bag for PlainDate
+features: [BigInt, Symbol, Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const primitiveTests = [
+ [undefined, "undefined"],
+ [null, "null"],
+ [true, "boolean"],
+ ["", "empty string"],
+ [1, "number that doesn't convert to a valid ISO string"],
+ [1n, "bigint"],
+];
+
+for (const [arg, description] of primitiveTests) {
+ assert.throws(
+ typeof arg === 'string' ? RangeError : TypeError,
+ () => instance.daysInYear(arg),
+ `${description} does not convert to a valid ISO string`
+ );
+}
+
+const typeErrorTests = [
+ [Symbol(), "symbol"],
+ [{}, "plain object"],
+ [Temporal.PlainDate, "Temporal.PlainDate, object"],
+ [Temporal.PlainDate.prototype, "Temporal.PlainDate.prototype, object"],
+];
+
+for (const [arg, description] of typeErrorTests) {
+ assert.throws(TypeError, () => instance.daysInYear(arg), `${description} is not a valid property bag and does not convert to a string`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-zoneddatetime-convert.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-zoneddatetime-convert.js
new file mode 100644
index 0000000000..3788acb0b0
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-zoneddatetime-convert.js
@@ -0,0 +1,22 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinyear
+description: An exception from TimeZone#getOffsetNanosecondsFor() is propagated.
+features: [Temporal]
+---*/
+
+class TZ extends Temporal.TimeZone {
+ constructor() { super("UTC") }
+ getOffsetNanosecondsFor() { throw new Test262Error() }
+}
+
+const tz = new TZ();
+const arg = new Temporal.ZonedDateTime(0n, tz);
+const instance = new Temporal.Calendar("iso8601");
+
+assert.throws(Test262Error, () => instance.daysInYear(arg));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-zoneddatetime-slots.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-zoneddatetime-slots.js
new file mode 100644
index 0000000000..806c8a0da8
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-zoneddatetime-slots.js
@@ -0,0 +1,40 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinyear
+description: Getters are not called when converting a ZonedDateTime to a PlainDate.
+includes: [compareArray.js]
+features: [Temporal]
+---*/
+
+const actual = [];
+const prototypeDescrs = Object.getOwnPropertyDescriptors(Temporal.ZonedDateTime.prototype);
+const getters = ["year", "month", "monthCode", "day", "hour", "minute", "second", "millisecond", "microsecond", "nanosecond", "calendar"];
+
+for (const property of getters) {
+ Object.defineProperty(Temporal.ZonedDateTime.prototype, property, {
+ get() {
+ actual.push(`get ${property}`);
+ const value = prototypeDescrs[property].get.call(this);
+ return {
+ toString() {
+ actual.push(`toString ${property}`);
+ return value.toString();
+ },
+ valueOf() {
+ actual.push(`valueOf ${property}`);
+ return value;
+ },
+ };
+ },
+ });
+}
+
+const arg = new Temporal.ZonedDateTime(0n, "UTC");
+const instance = new Temporal.Calendar("iso8601");
+instance.daysInYear(arg);
+assert.compareArray(actual, []);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js
new file mode 100644
index 0000000000..27c987cc47
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinyear
+description: RangeError thrown if time zone reports an offset that is not an integer number of nanoseconds
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+[3600_000_000_000.5, NaN, -Infinity, Infinity].forEach((wrongOffset) => {
+ const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset);
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ assert.throws(RangeError, () => calendar.daysInYear(datetime));
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js
new file mode 100644
index 0000000000..ba08e54bc6
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinyear
+description: TypeError thrown if timeZone.getOffsetNanosecondsFor is not callable
+features: [BigInt, Symbol, Temporal, arrow-function]
+---*/
+
+[undefined, null, true, Math.PI, 'string', Symbol('sym'), 42n, {}].forEach((notCallable) => {
+ const timeZone = new Temporal.TimeZone("UTC");
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ timeZone.getOffsetNanosecondsFor = notCallable;
+ assert.throws(
+ TypeError,
+ () => calendar.daysInYear(datetime),
+ `Uncallable ${notCallable === null ? 'null' : typeof notCallable} getOffsetNanosecondsFor should throw TypeError`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js
new file mode 100644
index 0000000000..f393a863b9
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinyear
+description: RangeError thrown if time zone reports an offset that is out of range
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+[-86400_000_000_000, 86400_000_000_000].forEach((wrongOffset) => {
+ const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset);
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ assert.throws(RangeError, () => calendar.daysInYear(datetime));
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js
new file mode 100644
index 0000000000..70ce4d3e49
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinyear
+description: TypeError thrown if time zone reports an offset that is not a Number
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+[
+ undefined,
+ null,
+ true,
+ "+01:00",
+ Symbol(),
+ 3600_000_000_000n,
+ {},
+ { valueOf() { return 3600_000_000_000; } },
+].forEach((wrongOffset) => {
+ const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset);
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ assert.throws(TypeError, () => calendar.daysInYear(datetime));
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/basic.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/basic.js
new file mode 100644
index 0000000000..75c610132f
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/basic.js
@@ -0,0 +1,20 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinyear
+description: Basic tests for daysInYear().
+features: [Temporal]
+---*/
+
+const iso = Temporal.Calendar.from("iso8601");
+const res = 365;
+assert.sameValue(iso.daysInYear(Temporal.PlainDate.from("1994-11-05")), res, "PlainDate");
+assert.sameValue(iso.daysInYear(Temporal.PlainDateTime.from("1994-11-05T08:15:30")), res, "PlainDateTime");
+assert.sameValue(iso.daysInYear(Temporal.PlainYearMonth.from("1994-11")), res, "PlainYearMonth");
+assert.sameValue(iso.daysInYear({ year: 1994, month: 11, day: 5 }), res, "property bag");
+assert.sameValue(iso.daysInYear("1994-11-05"), res, "string");
+assert.throws(TypeError, () => iso.daysInYear({ year: 2000 }), "property bag with missing properties");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/branding.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/branding.js
new file mode 100644
index 0000000000..803d4ac8c6
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/branding.js
@@ -0,0 +1,27 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinyear
+description: Throw a TypeError if the receiver is invalid
+features: [Symbol, Temporal]
+---*/
+
+const daysInYear = Temporal.Calendar.prototype.daysInYear;
+
+assert.sameValue(typeof daysInYear, "function");
+
+const args = [new Temporal.PlainDate(2000, 1, 1)];
+
+assert.throws(TypeError, () => daysInYear.apply(undefined, args), "undefined");
+assert.throws(TypeError, () => daysInYear.apply(null, args), "null");
+assert.throws(TypeError, () => daysInYear.apply(true, args), "true");
+assert.throws(TypeError, () => daysInYear.apply("", args), "empty string");
+assert.throws(TypeError, () => daysInYear.apply(Symbol(), args), "symbol");
+assert.throws(TypeError, () => daysInYear.apply(1, args), "1");
+assert.throws(TypeError, () => daysInYear.apply({}, args), "plain object");
+assert.throws(TypeError, () => daysInYear.apply(Temporal.Calendar, args), "Temporal.Calendar");
+assert.throws(TypeError, () => daysInYear.apply(Temporal.Calendar.prototype, args), "Temporal.Calendar.prototype");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/browser.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/browser.js
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/builtin.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/builtin.js
new file mode 100644
index 0000000000..32cbf094c4
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/builtin.js
@@ -0,0 +1,36 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinyear
+description: >
+ Tests that Temporal.Calendar.prototype.daysInYear
+ meets the requirements for built-in objects defined by the
+ introduction of chapter 17 of the ECMAScript Language Specification.
+info: |
+ Built-in functions that are not constructors do not have a "prototype" property unless
+ otherwise specified in the description of a particular function.
+
+ Unless specified otherwise, a built-in object that is callable as a function is a built-in
+ function object with the characteristics described in 10.3. Unless specified otherwise, the
+ [[Extensible]] internal slot of a built-in object initially has the value true.
+
+ Unless otherwise specified every built-in function and every built-in constructor has the
+ Function prototype object [...] as the value of its [[Prototype]] internal slot.
+features: [Temporal]
+---*/
+
+assert.sameValue(Object.isExtensible(Temporal.Calendar.prototype.daysInYear),
+ true, "Built-in objects must be extensible.");
+
+assert.sameValue(Object.prototype.toString.call(Temporal.Calendar.prototype.daysInYear),
+ "[object Function]", "Object.prototype.toString");
+
+assert.sameValue(Object.getPrototypeOf(Temporal.Calendar.prototype.daysInYear),
+ Function.prototype, "prototype");
+
+assert.sameValue(Temporal.Calendar.prototype.daysInYear.hasOwnProperty("prototype"),
+ false, "prototype property");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/calendar-datefromfields-called-with-options-undefined.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/calendar-datefromfields-called-with-options-undefined.js
new file mode 100644
index 0000000000..7d7c2c34ec
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/calendar-datefromfields-called-with-options-undefined.js
@@ -0,0 +1,18 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinyear
+description: >
+ Calendar.dateFromFields method is called with undefined as the options value
+ when call originates internally
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions();
+calendar.daysInYear({ year: 2000, month: 5, day: 3, calendar });
+assert.sameValue(calendar.dateFromFieldsCallCount, 1);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/calendar-fields-iterable.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/calendar-fields-iterable.js
new file mode 100644
index 0000000000..8c09cdeb78
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/calendar-fields-iterable.js
@@ -0,0 +1,37 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinyear
+description: Verify the result of calendar.fields() is treated correctly.
+info: |
+ sec-temporal.calendar.prototype.daysinyear step 4:
+ 4. Let _year_ be ? ISOYear(_dateOrDateTime_).
+ sec-temporal-isoyear step 1.a:
+ a. Set _dateOrDateTime_ to ? ToTemporalDate(_dateOrDateTime_).
+ sec-temporal-totemporaldate step 2.c:
+ c. Let _fieldNames_ be ? CalendarFields(_calendar_, « *"day"*, *"month"*, *"monthCode"*, *"year"* »).
+ sec-temporal-calendarfields step 4:
+ 4. Let _result_ be ? IterableToListOfType(_fieldsArray_, « String »).
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const expected = [
+ "day",
+ "month",
+ "monthCode",
+ "year",
+];
+
+const calendar1 = TemporalHelpers.calendarFieldsIterable();
+const calendar2 = TemporalHelpers.calendarFieldsIterable();
+calendar1.daysInYear({ year: 2000, month: 5, day: 2, calendar: calendar2 });
+
+assert.sameValue(calendar1.fieldsCallCount, 0, "fields() method not called");
+assert.sameValue(calendar2.fieldsCallCount, 1, "fields() method called once");
+assert.compareArray(calendar2.fieldsCalledWith[0], expected, "fields() method called with correct args");
+assert(calendar2.iteratorExhausted[0], "iterated through the whole iterable");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/calendar-temporal-object.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/calendar-temporal-object.js
new file mode 100644
index 0000000000..47db820adf
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/calendar-temporal-object.js
@@ -0,0 +1,31 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinyear
+description: Fast path for converting other Temporal objects to Temporal.Calendar by reading internal slots
+info: |
+ sec-temporal.calendar.prototype.daysinyear step 4:
+ 4. Let _year_ be ? ISOYear(_dateOrDateTime_).
+ sec-temporal-isoyear step 1.a:
+ a. Set _dateOrDateTime_ to ? ToTemporalDate(_dateOrDateTime_).
+ sec-temporal-totemporaldate step 2.c:
+ c. Let _calendar_ be ? GetTemporalCalendarWithISODefault(_item_).
+ sec-temporal-gettemporalcalendarwithisodefault step 2:
+ 2. Return ? ToTemporalCalendarWithISODefault(_calendar_).
+ sec-temporal-totemporalcalendarwithisodefault step 2:
+ 3. Return ? ToTemporalCalendar(_temporalCalendarLike_).
+ sec-temporal-totemporalcalendar step 1.a:
+ a. If _temporalCalendarLike_ has an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]], [[InitializedTemporalMonthDay]], [[InitializedTemporalYearMonth]], or [[InitializedTemporalZonedDateTime]] internal slot, then
+ i. Return _temporalCalendarLike_.[[Calendar]].
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+TemporalHelpers.checkToTemporalCalendarFastPath((temporalObject) => {
+ const calendar = new Temporal.Calendar("iso8601");
+ calendar.daysInYear({ year: 2000, month: 5, day: 2, calendar: temporalObject });
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/infinity-throws-rangeerror.js
new file mode 100644
index 0000000000..5c3b5b8bb2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/infinity-throws-rangeerror.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: Throws if any value in the property bag is Infinity or -Infinity
+esid: sec-temporal.calendar.prototype.daysinyear
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+const base = { year: 2000, month: 5, day: 2 };
+
+[Infinity, -Infinity].forEach((inf) => {
+ ["year", "month", "day"].forEach((prop) => {
+ assert.throws(RangeError, () => instance.daysInYear({ ...base, [prop]: inf }), `${prop} property cannot be ${inf}`);
+
+ const calls = [];
+ const obj = TemporalHelpers.toPrimitiveObserver(calls, inf, prop);
+ assert.throws(RangeError, () => instance.daysInYear({ ...base, [prop]: obj }));
+ assert.compareArray(calls, [`get ${prop}.valueOf`, `call ${prop}.valueOf`], "it fails after fetching the primitive value");
+ });
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/length.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/length.js
new file mode 100644
index 0000000000..abf641692b
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/length.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2020 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinyear
+description: Temporal.Calendar.prototype.daysInYear.length is 1
+info: |
+ Every built-in function object, including constructors, has a "length" property whose value is
+ an integer. Unless otherwise specified, this value is equal to the largest number of named
+ arguments shown in the subclause headings for the function description. Optional parameters
+ (which are indicated with brackets: [ ]) or rest parameters (which are shown using the form
+ «...name») are not included in the default argument count.
+
+ Unless otherwise specified, the "length" property of a built-in function object has the
+ attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+verifyProperty(Temporal.Calendar.prototype.daysInYear, "length", {
+ value: 1,
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/name.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/name.js
new file mode 100644
index 0000000000..62a1d4ca2c
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/name.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinyear
+description: Temporal.Calendar.prototype.daysInYear.name is "daysInYear".
+info: |
+ Every built-in function object, including constructors, that is not identified as an anonymous
+ function has a "name" property whose value is a String. Unless otherwise specified, this value
+ is the name that is given to the function in this specification.
+
+ Unless otherwise specified, the "name" property of a built-in function object, if it exists,
+ has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+verifyProperty(Temporal.Calendar.prototype.daysInYear, "name", {
+ value: "daysInYear",
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/not-a-constructor.js
new file mode 100644
index 0000000000..a601f0132a
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/not-a-constructor.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinyear
+description: >
+ Temporal.Calendar.prototype.daysInYear does not implement [[Construct]], is not new-able
+info: |
+ Built-in function objects that are not identified as constructors do not implement the
+ [[Construct]] internal method unless otherwise specified in the description of a particular
+ function.
+includes: [isConstructor.js]
+features: [Reflect.construct, Temporal]
+---*/
+
+assert.throws(TypeError, () => {
+ new Temporal.Calendar.prototype.daysInYear();
+}, "Calling as constructor");
+
+assert.sameValue(isConstructor(Temporal.Calendar.prototype.daysInYear), false,
+ "isConstructor(Temporal.Calendar.prototype.daysInYear)");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/plain-date-time.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/plain-date-time.js
new file mode 100644
index 0000000000..8782edd51b
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/plain-date-time.js
@@ -0,0 +1,94 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.daysinyear
+description: >
+ Temporal.Calendar.prototype.daysInYear will take PlainDateTime and return
+ the number of days in a year.
+info: |
+ 4. If Type(temporalDateLike) is not Object or temporalDateLike does not have an [[InitializedTemporalDate]] or [[InitializedTemporalYearMonth]] internal slot, then
+ a. Set temporalDateLike to ? ToTemporalDate(temporalDateLike).
+ 5. Return 𝔽(! ISODaysInYear(temporalDateLike.[[ISOYear]])).
+features: [Temporal]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+let dt = new Temporal.PlainDateTime(1995, 8, 23, 5, 30, 13);
+assert.sameValue(
+ cal.daysInYear(dt),
+ 365,
+ 'cal.daysInYear(new Temporal.PlainDateTime(1995, 8, 23, 5, 30, 13)) must return 365'
+);
+
+dt = new Temporal.PlainDateTime(1996, 8, 23, 5, 30, 13);
+assert.sameValue(
+ cal.daysInYear(dt),
+ 366,
+ 'cal.daysInYear(new Temporal.PlainDateTime(1996, 8, 23, 5, 30, 13)) must return 366'
+);
+
+dt = new Temporal.PlainDateTime(1997, 8, 23, 5, 30, 13);
+assert.sameValue(
+ cal.daysInYear(dt),
+ 365,
+ 'cal.daysInYear(new Temporal.PlainDateTime(1997, 8, 23, 5, 30, 13)) must return 365'
+);
+
+dt = new Temporal.PlainDateTime(1998, 8, 23, 5, 30, 13);
+assert.sameValue(
+ cal.daysInYear(dt),
+ 365,
+ 'cal.daysInYear(new Temporal.PlainDateTime(1998, 8, 23, 5, 30, 13)) must return 365'
+);
+
+dt = new Temporal.PlainDateTime(1999, 8, 23, 5, 30, 13);
+assert.sameValue(
+ cal.daysInYear(dt),
+ 365,
+ 'cal.daysInYear(new Temporal.PlainDateTime(1999, 8, 23, 5, 30, 13)) must return 365'
+);
+
+dt = new Temporal.PlainDateTime(2000, 8, 23, 5, 30, 13);
+assert.sameValue(
+ cal.daysInYear(dt),
+ 366,
+ 'cal.daysInYear(new Temporal.PlainDateTime(2000, 8, 23, 5, 30, 13)) must return 366'
+);
+
+dt = new Temporal.PlainDateTime(2001, 8, 23, 5, 30, 13);
+assert.sameValue(
+ cal.daysInYear(dt),
+ 365,
+ 'cal.daysInYear(new Temporal.PlainDateTime(2001, 8, 23, 5, 30, 13)) must return 365'
+);
+
+dt = new Temporal.PlainDateTime(2002, 8, 23, 5, 30, 13);
+assert.sameValue(
+ cal.daysInYear(dt),
+ 365,
+ 'cal.daysInYear(new Temporal.PlainDateTime(2002, 8, 23, 5, 30, 13)) must return 365'
+);
+
+dt = new Temporal.PlainDateTime(2003, 8, 23, 5, 30, 13);
+assert.sameValue(
+ cal.daysInYear(dt),
+ 365,
+ 'cal.daysInYear(new Temporal.PlainDateTime(2003, 8, 23, 5, 30, 13)) must return 365'
+);
+
+dt = new Temporal.PlainDateTime(2004, 8, 23, 5, 30, 13);
+assert.sameValue(
+ cal.daysInYear(dt),
+ 366,
+ 'cal.daysInYear(new Temporal.PlainDateTime(2004, 8, 23, 5, 30, 13)) must return 366'
+);
+
+dt = new Temporal.PlainDateTime(2005, 8, 23, 5, 30, 13);
+assert.sameValue(
+ cal.daysInYear(dt),
+ 365,
+ 'cal.daysInYear(new Temporal.PlainDateTime(2005, 8, 23, 5, 30, 13)) must return 365'
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/plain-date.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/plain-date.js
new file mode 100644
index 0000000000..54b3383c1e
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/plain-date.js
@@ -0,0 +1,48 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.daysinyear
+description: >
+ Temporal.Calendar.prototype.daysInYear will take PlainDate and return
+ the number of days in a year.
+info: |
+ 5. Return 𝔽(! ISODaysInYear(temporalDateLike.[[ISOYear]])).
+features: [Temporal]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+let d = new Temporal.PlainDate(1995, 7, 15);
+assert.sameValue(cal.daysInYear(d), 365, 'cal.daysInYear(new Temporal.PlainDate(1995, 7, 15)) must return 365');
+
+d = new Temporal.PlainDate(1996, 7, 15);
+assert.sameValue(cal.daysInYear(d), 366, 'cal.daysInYear(new Temporal.PlainDate(1996, 7, 15)) must return 366');
+
+d = new Temporal.PlainDate(1997, 7, 15);
+assert.sameValue(cal.daysInYear(d), 365, 'cal.daysInYear(new Temporal.PlainDate(1997, 7, 15)) must return 365');
+
+d = new Temporal.PlainDate(1998, 7, 15);
+assert.sameValue(cal.daysInYear(d), 365, 'cal.daysInYear(new Temporal.PlainDate(1998, 7, 15)) must return 365');
+
+d = new Temporal.PlainDate(1999, 7, 15);
+assert.sameValue(cal.daysInYear(d), 365, 'cal.daysInYear(new Temporal.PlainDate(1999, 7, 15)) must return 365');
+
+d = new Temporal.PlainDate(2000, 7, 15);
+assert.sameValue(cal.daysInYear(d), 366, 'cal.daysInYear(new Temporal.PlainDate(2000, 7, 15)) must return 366');
+
+d = new Temporal.PlainDate(2001, 7, 15);
+assert.sameValue(cal.daysInYear(d), 365, 'cal.daysInYear(new Temporal.PlainDate(2001, 7, 15)) must return 365');
+
+d = new Temporal.PlainDate(2002, 7, 15);
+assert.sameValue(cal.daysInYear(d), 365, 'cal.daysInYear(new Temporal.PlainDate(2002, 7, 15)) must return 365');
+
+d = new Temporal.PlainDate(2003, 7, 15);
+assert.sameValue(cal.daysInYear(d), 365, 'cal.daysInYear(new Temporal.PlainDate(2003, 7, 15)) must return 365');
+
+d = new Temporal.PlainDate(2004, 7, 15);
+assert.sameValue(cal.daysInYear(d), 366, 'cal.daysInYear(new Temporal.PlainDate(2004, 7, 15)) must return 366');
+
+d = new Temporal.PlainDate(2005, 7, 15);
+assert.sameValue(cal.daysInYear(d), 365, 'cal.daysInYear(new Temporal.PlainDate(2005, 7, 15)) must return 365');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/prop-desc.js
new file mode 100644
index 0000000000..77e93a567c
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/prop-desc.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinyear
+description: The "daysInYear" property of Temporal.Calendar.prototype
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+assert.sameValue(
+ typeof Temporal.Calendar.prototype.daysInYear,
+ "function",
+ "`typeof Calendar.prototype.daysInYear` is `function`"
+);
+
+verifyProperty(Temporal.Calendar.prototype, "daysInYear", {
+ writable: true,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/shell.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/shell.js
new file mode 100644
index 0000000000..eda1477282
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/shell.js
@@ -0,0 +1,24 @@
+// GENERATED, DO NOT EDIT
+// file: isConstructor.js
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: |
+ Test if a given function is a constructor function.
+defines: [isConstructor]
+features: [Reflect.construct]
+---*/
+
+function isConstructor(f) {
+ if (typeof f !== "function") {
+ throw new Test262Error("isConstructor invoked with a non-function value");
+ }
+
+ try {
+ Reflect.construct(function(){}, [], f);
+ } catch (e) {
+ return false;
+ }
+ return true;
+}
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/string.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/string.js
new file mode 100644
index 0000000000..f1697e8fc9
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/string.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.daysinyear
+description: >
+ Temporal.Calendar.prototype.daysInYear will take PlainDate and return
+ the number of days in a year.
+info: |
+ 4. If Type(temporalDateLike) is not Object or temporalDateLike does not have an [[InitializedTemporalDate]] or [[InitializedTemporalYearMonth]] internal slot, then
+ a. Set temporalDateLike to ? ToTemporalDate(temporalDateLike).
+ 5. Return 𝔽(! ISODaysInYear(temporalDateLike.[[ISOYear]])).
+features: [Temporal]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+assert.sameValue(cal.daysInYear("2019-03-18"), 365, 'cal.daysInYear("2019-03-18") must return 365');
+assert.sameValue(cal.daysInYear("2020-03-18"), 366, 'cal.daysInYear("2020-03-18") must return 366');
+assert.sameValue(cal.daysInYear("2021-03-18"), 365, 'cal.daysInYear("2021-03-18") must return 365');
+assert.sameValue(cal.daysInYear("2022-03-18"), 365, 'cal.daysInYear("2022-03-18") must return 365');
+assert.sameValue(cal.daysInYear("2023-03-18"), 365, 'cal.daysInYear("2023-03-18") must return 365');
+assert.sameValue(cal.daysInYear("2024-03-18"), 366, 'cal.daysInYear("2024-03-18") must return 366');
+assert.sameValue(cal.daysInYear("2025-03-18"), 365, 'cal.daysInYear("2025-03-18") must return 365');
+assert.sameValue(cal.daysInYear("2026-03-18"), 365, 'cal.daysInYear("2026-03-18") must return 365');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/throw-range-error-ToTemporalDate.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/throw-range-error-ToTemporalDate.js
new file mode 100644
index 0000000000..40fff73941
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/throw-range-error-ToTemporalDate.js
@@ -0,0 +1,21 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.daysInYear
+description: >
+ Temporal.Calendar.prototype.daysInYear throws RangeError on
+ ToTemporalDate when temporalDateLike is invalid string.
+info: |
+ 4. If Type(temporalDateLike) is not Object or temporalDateLike does
+ not have an [[InitializedTemporalDate]] or [[InitializedTemporalYearMonth]]
+ internal slot, then
+ a. Set temporalDateLike to ? ToTemporalDate(temporalDateLike).
+features: [Temporal, arrow-function]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+assert.throws(RangeError, () => cal.daysInYear("invalid string"),
+ 'cal.daysInYear("invalid string") throws a RangeError exception');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/year-zero.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/year-zero.js
new file mode 100644
index 0000000000..8fd8c110a9
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInYear/year-zero.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinyear
+description: Negative zero, as an extended year, is rejected
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ "-000000-10-31",
+ "-000000-10-31T00:45",
+ "-000000-10-31T00:45+01:00",
+ "-000000-10-31T00:45+00:00[UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.daysInYear(arg),
+ "reject minus zero as extended year"
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/argument-iterable-not-array.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/argument-iterable-not-array.js
new file mode 100644
index 0000000000..ead494c99e
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/argument-iterable-not-array.js
@@ -0,0 +1,30 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.fields
+description: A non-Array iterable passed as the argument is exhausted
+info: |
+ sec-temporal.calendar.prototype.fields step 4:
+ 4. Let _fieldNames_ be ? IterableToList(_fields_).
+includes: [compareArray.js]
+features: [Temporal]
+---*/
+
+const fieldNames = ["day", "month", "monthCode", "year"];
+const iterable = {
+ iteratorExhausted: false,
+ *[Symbol.iterator]() {
+ yield* fieldNames;
+ this.iteratorExhausted = true;
+ },
+};
+
+const calendar = new Temporal.Calendar("iso8601");
+const result = calendar.fields(iterable);
+
+assert.compareArray(result, fieldNames);
+assert(iterable.iteratorExhausted);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/argument-throws-duplicate-keys.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/argument-throws-duplicate-keys.js
new file mode 100644
index 0000000000..be868d3bf7
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/argument-throws-duplicate-keys.js
@@ -0,0 +1,31 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.fields
+description: Duplicate fields are not allowed in the argument to Calendar.prototype.fields
+info: |
+ sec-temporal.calendar.prototype.fields step 7.b.iii:
+ iii. If _fieldNames_ contains _nextValue_, then
+ 1. Let _completion_ be ThrowCompletion(a newly created *RangeError* object).
+ 2. Return ? IteratorClose(_iteratorRecord_, _completion_).
+features: [Temporal]
+---*/
+
+const calendar = new Temporal.Calendar("iso8601");
+assert.throws(RangeError, () => calendar.fields(["day", "month", "day"]));
+assert.throws(RangeError, () => calendar.fields(["year", "month", "monthCode", "day", "year"]));
+
+const manyFields = {
+ count: 0
+};
+
+manyFields[Symbol.iterator] = function*() {
+ while (this.count++ < 100) yield "year";
+};
+
+assert.throws(RangeError, () => calendar.fields(manyFields), "Rejected duplicate values");
+assert.sameValue(manyFields.count, 2, "Rejected first duplicate value");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/argument-throws-invalid-keys.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/argument-throws-invalid-keys.js
new file mode 100644
index 0000000000..81bc2e5d64
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/argument-throws-invalid-keys.js
@@ -0,0 +1,46 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.fields
+description: >
+ Calendar.prototype.fields rejects input field names that are not singular
+ names of Temporal date units
+info: |
+ sec-temporal.calendar.prototype.fields step 7.b.ii:
+ 7. Repeat, while next is not false,
+ a. Set next to ? IteratorStep(iteratorRecord).
+ b. If next is not false, then
+ i. Let nextValue be ? IteratorValue(next).
+ ii. If Type(nextValue) is not String, then
+ 1. Let completion be ThrowCompletion(a newly created TypeError object).
+ 2. Return ? IteratorClose(iteratorRecord, completion).
+ sec-temporal.calendar.prototype.fields step 7.b.iv:
+ iv. If _nextValue_ is not one of *"year"*, *"month"*, *"monthCode"*, or *"day"*, then
+ 1. Let _completion_ be ThrowCompletion(a newly created *RangeError* object).
+ 2. Return ? IteratorClose(_iteratorRecord_, _completion_).
+
+features: [Temporal]
+---*/
+
+const calendar = new Temporal.Calendar("iso8601");
+assert.throws(TypeError, () => calendar.fields([1]));
+assert.throws(TypeError, () => calendar.fields([1n]));
+assert.throws(TypeError, () => calendar.fields([Symbol('foo')]));
+assert.throws(TypeError, () => calendar.fields([true]));
+assert.throws(TypeError, () => calendar.fields([null]));
+assert.throws(TypeError, () => calendar.fields([{}]));
+assert.throws(TypeError, () => calendar.fields([undefined]));
+assert.throws(TypeError, () => calendar.fields(["day", 1]));
+assert.throws(RangeError, () => calendar.fields(["hour"]));
+assert.throws(RangeError, () => calendar.fields(["minute"]));
+assert.throws(RangeError, () => calendar.fields(["second"]));
+assert.throws(RangeError, () => calendar.fields(["millisecond"]));
+assert.throws(RangeError, () => calendar.fields(["microsecond"]));
+assert.throws(RangeError, () => calendar.fields(["nanosecond"]));
+assert.throws(RangeError, () => calendar.fields(["month", "days"]));
+assert.throws(RangeError, () => calendar.fields(["days"]));
+assert.throws(RangeError, () => calendar.fields(["people"]));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/branding.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/branding.js
new file mode 100644
index 0000000000..fbfb89f314
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/branding.js
@@ -0,0 +1,27 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.fields
+description: Throw a TypeError if the receiver is invalid
+features: [Symbol, Temporal]
+---*/
+
+const fields = Temporal.Calendar.prototype.fields;
+
+assert.sameValue(typeof fields, "function");
+
+const args = [[]];
+
+assert.throws(TypeError, () => fields.apply(undefined, args), "undefined");
+assert.throws(TypeError, () => fields.apply(null, args), "null");
+assert.throws(TypeError, () => fields.apply(true, args), "true");
+assert.throws(TypeError, () => fields.apply("", args), "empty string");
+assert.throws(TypeError, () => fields.apply(Symbol(), args), "symbol");
+assert.throws(TypeError, () => fields.apply(1, args), "1");
+assert.throws(TypeError, () => fields.apply({}, args), "plain object");
+assert.throws(TypeError, () => fields.apply(Temporal.Calendar, args), "Temporal.Calendar");
+assert.throws(TypeError, () => fields.apply(Temporal.Calendar.prototype, args), "Temporal.Calendar.prototype");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/browser.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/browser.js
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/builtin.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/builtin.js
new file mode 100644
index 0000000000..5c8387cd05
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/builtin.js
@@ -0,0 +1,36 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.fields
+description: >
+ Tests that Temporal.Calendar.prototype.fields
+ meets the requirements for built-in objects defined by the
+ introduction of chapter 17 of the ECMAScript Language Specification.
+info: |
+ Built-in functions that are not constructors do not have a "prototype" property unless
+ otherwise specified in the description of a particular function.
+
+ Unless specified otherwise, a built-in object that is callable as a function is a built-in
+ function object with the characteristics described in 10.3. Unless specified otherwise, the
+ [[Extensible]] internal slot of a built-in object initially has the value true.
+
+ Unless otherwise specified every built-in function and every built-in constructor has the
+ Function prototype object [...] as the value of its [[Prototype]] internal slot.
+features: [Temporal]
+---*/
+
+assert.sameValue(Object.isExtensible(Temporal.Calendar.prototype.fields),
+ true, "Built-in objects must be extensible.");
+
+assert.sameValue(Object.prototype.toString.call(Temporal.Calendar.prototype.fields),
+ "[object Function]", "Object.prototype.toString");
+
+assert.sameValue(Object.getPrototypeOf(Temporal.Calendar.prototype.fields),
+ Function.prototype, "prototype");
+
+assert.sameValue(Temporal.Calendar.prototype.fields.hasOwnProperty("prototype"),
+ false, "prototype property");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/length.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/length.js
new file mode 100644
index 0000000000..312c745db3
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/length.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.fields
+description: Temporal.Calendar.prototype.fields.length is 1
+info: |
+ Every built-in function object, including constructors, has a "length" property whose value is
+ an integer. Unless otherwise specified, this value is equal to the largest number of named
+ arguments shown in the subclause headings for the function description. Optional parameters
+ (which are indicated with brackets: [ ]) or rest parameters (which are shown using the form
+ «...name») are not included in the default argument count.
+
+ Unless otherwise specified, the "length" property of a built-in function object has the
+ attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+verifyProperty(Temporal.Calendar.prototype.fields, "length", {
+ value: 1,
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/long-input.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/long-input.js
new file mode 100644
index 0000000000..88410f3d05
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/long-input.js
@@ -0,0 +1,50 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.fields
+description: >
+ Temporal.Calendar.prototype.fields will throw when its input iterable yields an
+ invalid field.
+info: |
+ ## 12.4.21 Temporal.Calendar.prototype.fields ( fields )
+ 1. Let calendar be the this value.
+ 2. Perform ? RequireInternalSlot(calendar, [[InitializedTemporalCalendar]]).
+ 4. Let iteratorRecord be ? Getiterator(fields, sync).
+ 5. Let fieldNames be a new empty List.
+ 6. Let next be true.
+ 7. Repeat, while next is not false,
+ a. Set next to ? IteratorStep(iteratorRecord).
+ b. If next is not false, then
+ i. Let nextValue be ? IteratorValue(next).
+ iv. If nextValue is not one of "year", "month", "monthCode", or "day", then
+ 1. Let completion be ThrowCompletion(a newly created RangeError object).
+ 2. Return ? IteratorClose(iteratorRecord, completion).
+features: [Symbol, Symbol.iterator, Temporal, computed-property-names, generators]
+---*/
+let cal = new Temporal.Calendar("iso8601")
+let i = 0;
+const fields = {
+ *[Symbol.iterator]() {
+ // The first three are valid values
+ yield "year";
+ i++;
+ yield "month";
+ i++;
+ yield "monthCode";
+ i++;
+ // The fourth one is wrong and should throw after the next line.
+ yield "garbage";
+ // The following three lines should not be reached if the implemention
+ // correctly check the previous line.
+ i++;
+ yield "day";
+ i++;
+ }
+}
+assert.throws(RangeError, () => cal.fields(fields), "Garbage content");
+// stop after the third one.
+assert.sameValue(i, 3);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/name.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/name.js
new file mode 100644
index 0000000000..16a1efe247
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/name.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.fields
+description: Temporal.Calendar.prototype.fields.name is "fields".
+info: |
+ Every built-in function object, including constructors, that is not identified as an anonymous
+ function has a "name" property whose value is a String. Unless otherwise specified, this value
+ is the name that is given to the function in this specification.
+
+ Unless otherwise specified, the "name" property of a built-in function object, if it exists,
+ has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+verifyProperty(Temporal.Calendar.prototype.fields, "name", {
+ value: "fields",
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/non-string-element-throws.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/non-string-element-throws.js
new file mode 100644
index 0000000000..c7627ff747
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/non-string-element-throws.js
@@ -0,0 +1,20 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.fields
+description: TypeError thrown if the input iterable yields a non-String value
+info: |
+ sec-temporal.calendar.prototype.fields step 5:
+ 5. For each element _fieldName_ of _fieldNames_, do
+ a. If Type(_fieldName_) is not String, throw a *TypeError* exception.
+features: [Temporal]
+---*/
+
+const calendar = new Temporal.Calendar("iso8601");
+[true, 3, 3n, {}, () => {}, Symbol(), undefined, null].forEach((element) => {
+ assert.throws(TypeError, () => calendar.fields([element]), "bad input to calendar.fields()");
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/not-a-constructor.js
new file mode 100644
index 0000000000..da8317c185
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/not-a-constructor.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.fields
+description: >
+ Temporal.Calendar.prototype.fields does not implement [[Construct]], is not new-able
+info: |
+ Built-in function objects that are not identified as constructors do not implement the
+ [[Construct]] internal method unless otherwise specified in the description of a particular
+ function.
+includes: [isConstructor.js]
+features: [Reflect.construct, Temporal]
+---*/
+
+assert.throws(TypeError, () => {
+ new Temporal.Calendar.prototype.fields();
+}, "Calling as constructor");
+
+assert.sameValue(isConstructor(Temporal.Calendar.prototype.fields), false,
+ "isConstructor(Temporal.Calendar.prototype.fields)");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/prop-desc.js
new file mode 100644
index 0000000000..4461f5bd3c
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/prop-desc.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.fields
+description: The "fields" property of Temporal.Calendar.prototype
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+assert.sameValue(
+ typeof Temporal.Calendar.prototype.fields,
+ "function",
+ "`typeof Calendar.prototype.fields` is `function`"
+);
+
+verifyProperty(Temporal.Calendar.prototype, "fields", {
+ writable: true,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/repeated-throw.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/repeated-throw.js
new file mode 100644
index 0000000000..58bb67dc6c
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/repeated-throw.js
@@ -0,0 +1,58 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.fields
+description: >
+ Temporal.Calendar.prototype.fields will throw if its input iterable yields
+ the same value twice.
+info: |
+ ## 12.4.21 Temporal.Calendar.prototype.fields ( fields )
+ 1. Let calendar be the this value.
+ 2. Perform ? RequireInternalSlot(calendar, [[InitializedTemporalCalendar]]).
+ 4. Let iteratorRecord be ? Getiterator(fields, sync).
+ 5. Let fieldNames be a new empty List.
+ 6. Let next be true.
+ 7. Repeat, while next is not false,
+ a. Set next to ? IteratorStep(iteratorRecord).
+ b. If next is not false, then
+ i. Let nextValue be ? IteratorValue(next).
+ iii. If fieldNames contains nextValue, then
+ 1. Let completion be ThrowCompletion(a newly created RangeError object).
+ 2. Return ? IteratorClose(iteratorRecord, completion).
+features: [Symbol, Symbol.iterator, Temporal, computed-property-names, generators]
+---*/
+let cal = new Temporal.Calendar("iso8601")
+let i = 0;
+const fields = {
+ *[Symbol.iterator]() {
+ yield "month";
+ i++;
+ yield "year";
+ i++;
+ yield "year";
+ i++;
+ }
+}
+assert.throws(
+ RangeError, () => cal.fields(fields), "repeated valid value should throw");
+assert.sameValue(i, 2, "Should stop at 2");
+
+// Test all valid values will throw when repeated
+[ "day", "monthCode", "month", "year" ].forEach((f) => {
+ i = 0;
+ const fields2 = {
+ *[Symbol.iterator]() {
+ yield f;
+ i++;
+ yield f;
+ i++;
+ }
+ }
+ assert.throws(
+ RangeError, () => cal.fields(fields2), "repeated valid value should throw");
+ assert.sameValue(i, 1, "Should stop at 1");
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/reverse.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/reverse.js
new file mode 100644
index 0000000000..88a1721cfd
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/reverse.js
@@ -0,0 +1,39 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.fields
+description: >
+ Temporal.Calendar.prototype.fields will return the iterable in array if all
+ input are valid regardless of it's order.
+info: |
+ ## 12.4.21 Temporal.Calendar.prototype.fields ( fields )
+ 1. Let calendar be the this value.
+ 2. Perform ? RequireInternalSlot(calendar, [[InitializedTemporalCalendar]]).
+ 4. Let iteratorRecord be ? Getiterator(fields, sync).
+ 5. Let fieldNames be a new empty List.
+ 6. Let next be true.
+ 7. Repeat, while next is not false,
+ a. Set next to ? IteratorStep(iteratorRecord).
+ b. If next is not false, then
+ i. Let nextValue be ? IteratorValue(next).
+ iv. If nextValue is not one of "year", "month", "monthCode", or "day", then
+ 1. Let completion be ThrowCompletion(a newly created RangeError object).
+ 2. Return ? IteratorClose(iteratorRecord, completion).
+features: [Symbol, Symbol.iterator, Temporal, computed-property-names, generators]
+includes: [compareArray.js]
+---*/
+let cal = new Temporal.Calendar("iso8601")
+const fields = {
+ *[Symbol.iterator]() {
+ yield "day";
+ yield "monthCode";
+ yield "month";
+ yield "year";
+ }
+}
+assert.compareArray(cal.fields(fields), Array.from(fields),
+ 'valid fields should be supported even if they are in reversed order of the spec');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/shell.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/shell.js
new file mode 100644
index 0000000000..eda1477282
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/fields/shell.js
@@ -0,0 +1,24 @@
+// GENERATED, DO NOT EDIT
+// file: isConstructor.js
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: |
+ Test if a given function is a constructor function.
+defines: [isConstructor]
+features: [Reflect.construct]
+---*/
+
+function isConstructor(f) {
+ if (typeof f !== "function") {
+ throw new Test262Error("isConstructor invoked with a non-function value");
+ }
+
+ try {
+ Reflect.construct(function(){}, [], f);
+ } catch (e) {
+ return false;
+ }
+ return true;
+}
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/id/branding.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/id/branding.js
new file mode 100644
index 0000000000..447fe2b6c1
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/id/branding.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-get-temporal.calendar.prototype.id
+description: Throw a TypeError if the receiver is invalid
+features: [Symbol, Temporal]
+---*/
+
+const descriptor = Object.getOwnPropertyDescriptor(Temporal.Calendar.prototype, "id");
+const id = descriptor.get;
+
+assert.sameValue(typeof id, "function");
+
+assert.throws(TypeError, () => id.call(undefined), "undefined");
+assert.throws(TypeError, () => id.call(null), "null");
+assert.throws(TypeError, () => id.call(true), "true");
+assert.throws(TypeError, () => id.call(""), "empty string");
+assert.throws(TypeError, () => id.call(Symbol()), "symbol");
+assert.throws(TypeError, () => id.call(1), "1");
+assert.throws(TypeError, () => id.call({}), "plain object");
+assert.throws(TypeError, () => id.call(Temporal.Calendar), "Temporal.Calendar");
+assert.throws(TypeError, () => id.call(Temporal.Calendar.prototype), "Temporal.Calendar.prototype");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/id/browser.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/id/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/id/browser.js
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/id/custom-calendar.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/id/custom-calendar.js
new file mode 100644
index 0000000000..25e5499b48
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/id/custom-calendar.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-get-temporal.calendar.prototype.id
+description: Getter does not call toString(), returns the ID from internal slot
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const actual = [];
+const expected = [];
+
+const calendar = new Temporal.Calendar("iso8601");
+TemporalHelpers.observeProperty(actual, calendar, Symbol.toPrimitive, undefined);
+TemporalHelpers.observeProperty(actual, calendar, "toString", function () {
+ actual.push("call calendar.toString");
+ return "calendar ID";
+});
+
+const result = calendar.id;
+assert.compareArray(actual, expected);
+assert.sameValue(result, "iso8601");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/id/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/id/prop-desc.js
new file mode 100644
index 0000000000..13d41bea22
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/id/prop-desc.js
@@ -0,0 +1,17 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-get-temporal.calendar.prototype.id
+description: The "id" property of Temporal.Calendar.prototype
+features: [Temporal]
+---*/
+
+const descriptor = Object.getOwnPropertyDescriptor(Temporal.Calendar.prototype, "id");
+assert.sameValue(typeof descriptor.get, "function");
+assert.sameValue(descriptor.set, undefined);
+assert.sameValue(descriptor.enumerable, false);
+assert.sameValue(descriptor.configurable, true);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/id/shell.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/id/shell.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/id/shell.js
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-builtin-calendar-no-array-iteration.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-builtin-calendar-no-array-iteration.js
new file mode 100644
index 0000000000..8fa53a0782
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-builtin-calendar-no-array-iteration.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.inleapyear
+description: >
+ Calling the method with a property bag argument with a builtin calendar causes
+ no observable array iteration when getting the calendar fields.
+features: [Temporal]
+---*/
+
+const arrayPrototypeSymbolIteratorOriginal = Array.prototype[Symbol.iterator];
+Array.prototype[Symbol.iterator] = function arrayIterator() {
+ throw new Test262Error("Array should not be iterated");
+}
+
+const instance = new Temporal.Calendar("iso8601");
+const arg = { year: 2000, month: 5, day: 2, calendar: "iso8601" };
+instance.inLeapYear(arg);
+
+Array.prototype[Symbol.iterator] = arrayPrototypeSymbolIteratorOriginal;
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-calendar-datefromfields-called-with-null-prototype-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-calendar-datefromfields-called-with-null-prototype-fields.js
new file mode 100644
index 0000000000..e265505050
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-calendar-datefromfields-called-with-null-prototype-fields.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.inleapyear
+description: >
+ Calendar.dateFromFields method is called with a null-prototype fields object
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarCheckFieldsPrototypePollution();
+const instance = new Temporal.Calendar("iso8601");
+const arg = { year: 2000, month: 5, day: 2, calendar };
+instance.inLeapYear(arg);
+assert.sameValue(calendar.dateFromFieldsCallCount, 1, "dateFromFields should be called on the property bag's calendar");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-constructor-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-constructor-in-calendar-fields.js
new file mode 100644
index 0000000000..767c8ba1b2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-constructor-in-calendar-fields.js
@@ -0,0 +1,17 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.inleapyear
+description: If a calendar's fields() method returns a field named 'constructor', PrepareTemporalFields should throw a RangeError.
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarWithExtraFields(['constructor']);
+const arg = {year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar};
+const instance = new Temporal.Calendar("iso8601");
+
+assert.throws(RangeError, () => instance.inLeapYear(arg));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-duplicate-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-duplicate-calendar-fields.js
new file mode 100644
index 0000000000..30586d5b8e
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-duplicate-calendar-fields.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.inleapyear
+description: If a calendar's fields() method returns duplicate field names, PrepareTemporalFields should throw a RangeError.
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+for (const extra_fields of [['foo', 'foo'], ['day'], ['month'], ['monthCode'], ['year']]) {
+ const calendar = TemporalHelpers.calendarWithExtraFields(extra_fields);
+ const arg = { year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar };
+ const instance = new Temporal.Calendar("iso8601");
+
+ assert.throws(RangeError, () => instance.inLeapYear(arg));
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-leap-second.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-leap-second.js
new file mode 100644
index 0000000000..294783583a
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-leap-second.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.inleapyear
+description: Leap second is a valid ISO string for PlainDate
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+let arg = "2016-12-31T23:59:60";
+const result1 = instance.inLeapYear(arg);
+assert.sameValue(
+ result1,
+ true,
+ "leap second is a valid ISO string for PlainDate"
+);
+
+arg = { year: 2016, month: 12, day: 31, hour: 23, minute: 59, second: 60 };
+const result2 = instance.inLeapYear(arg);
+assert.sameValue(
+ result2,
+ true,
+ "second: 60 is ignored in property bag for PlainDate"
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-number.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-number.js
new file mode 100644
index 0000000000..0ee5fc83da
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-number.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.inleapyear
+description: A number cannot be used in place of a Temporal.PlainDate
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const numbers = [
+ 1,
+ 19761118,
+ -19761118,
+ 1234567890,
+];
+
+for (const arg of numbers) {
+ assert.throws(
+ TypeError,
+ () => instance.inLeapYear(arg),
+ 'Numbers cannot be used in place of an ISO string for PlainDate'
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-propertybag-calendar-case-insensitive.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-propertybag-calendar-case-insensitive.js
new file mode 100644
index 0000000000..5b4bf6c04f
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-propertybag-calendar-case-insensitive.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.inleapyear
+description: The calendar name is case-insensitive
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const calendar = "IsO8601";
+
+const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+const result = instance.inLeapYear(arg);
+assert.sameValue(result, true, "Calendar is case-insensitive");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-propertybag-calendar-leap-second.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-propertybag-calendar-leap-second.js
new file mode 100644
index 0000000000..d48face463
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-propertybag-calendar-leap-second.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.inleapyear
+description: Leap second is a valid ISO string for a calendar in a property bag
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const calendar = "2016-12-31T23:59:60";
+
+const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+const result = instance.inLeapYear(arg);
+assert.sameValue(
+ result,
+ true,
+ "leap second is a valid ISO string for calendar"
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-propertybag-calendar-number.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-propertybag-calendar-number.js
new file mode 100644
index 0000000000..32faae6439
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-propertybag-calendar-number.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.inleapyear
+description: A number as calendar in a property bag is not accepted
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const numbers = [
+ 1,
+ 19970327,
+ -19970327,
+ 1234567890,
+];
+
+for (const calendar of numbers) {
+ const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+ assert.throws(
+ TypeError,
+ () => instance.inLeapYear(arg),
+ "Numbers cannot be used as a calendar"
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-propertybag-calendar-string.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-propertybag-calendar-string.js
new file mode 100644
index 0000000000..5d3a595827
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-propertybag-calendar-string.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.inleapyear
+description: A calendar ID is valid input for Calendar
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const calendar = "iso8601";
+
+const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+const result = instance.inLeapYear(arg);
+assert.sameValue(result, true, `Calendar created from string "${calendar}"`);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-propertybag-calendar-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-propertybag-calendar-wrong-type.js
new file mode 100644
index 0000000000..fa0d34bb03
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-propertybag-calendar-wrong-type.js
@@ -0,0 +1,46 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.inleapyear
+description: >
+ Appropriate error thrown when a calendar property from a property bag cannot
+ be converted to a calendar object or string
+features: [BigInt, Symbol, Temporal]
+---*/
+
+const timeZone = new Temporal.TimeZone("UTC");
+const instance = new Temporal.Calendar("iso8601");
+
+const primitiveTests = [
+ [null, "null"],
+ [true, "boolean"],
+ ["", "empty string"],
+ [1, "number that doesn't convert to a valid ISO string"],
+ [1n, "bigint"],
+];
+
+for (const [calendar, description] of primitiveTests) {
+ const arg = { year: 2019, monthCode: "M11", day: 1, calendar };
+ assert.throws(
+ typeof calendar === 'string' ? RangeError : TypeError,
+ () => instance.inLeapYear(arg),
+ `${description} does not convert to a valid ISO string`
+ );
+}
+
+const typeErrorTests = [
+ [Symbol(), "symbol"],
+ [{}, "plain object that doesn't implement the protocol"],
+ [new Temporal.TimeZone("UTC"), "time zone instance"],
+ [Temporal.Calendar, "Temporal.Calendar, object"],
+ [Temporal.Calendar.prototype, "Temporal.Calendar.prototype, object"], // fails brand check in dateFromFields()
+];
+
+for (const [calendar, description] of typeErrorTests) {
+ const arg = { year: 2019, monthCode: "M11", day: 1, calendar };
+ assert.throws(TypeError, () => instance.inLeapYear(arg), `${description} is not a valid property bag and does not convert to a string`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-propertybag-calendar-year-zero.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-propertybag-calendar-year-zero.js
new file mode 100644
index 0000000000..0835539959
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-propertybag-calendar-year-zero.js
@@ -0,0 +1,27 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.inleapyear
+description: Negative zero, as an extended year, is rejected
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ "-000000-10-31",
+ "-000000-10-31T17:45",
+ "-000000-10-31T17:45Z",
+ "-000000-10-31T17:45+01:00",
+ "-000000-10-31T17:45+00:00[UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.inLeapYear(arg),
+ "reject minus zero as extended year"
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-proto-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-proto-in-calendar-fields.js
new file mode 100644
index 0000000000..c4b97957a5
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-proto-in-calendar-fields.js
@@ -0,0 +1,17 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.inleapyear
+description: If a calendar's fields() method returns a field named '__proto__', PrepareTemporalFields should throw a RangeError.
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarWithExtraFields(['__proto__']);
+const arg = {year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar};
+const instance = new Temporal.Calendar("iso8601");
+
+assert.throws(RangeError, () => instance.inLeapYear(arg));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string-calendar-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string-calendar-annotation.js
new file mode 100644
index 0000000000..bf2019e648
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string-calendar-annotation.js
@@ -0,0 +1,33 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.inleapyear
+description: Various forms of calendar annotation; critical flag has no effect
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02[u-ca=iso8601]", "without time or time zone"],
+ ["2000-05-02[UTC][u-ca=iso8601]", "with time zone and no time"],
+ ["2000-05-02T15:23[u-ca=iso8601]", "without time zone"],
+ ["2000-05-02T15:23[UTC][u-ca=iso8601]", "with time zone"],
+ ["2000-05-02T15:23[!u-ca=iso8601]", "with ! and no time zone"],
+ ["2000-05-02T15:23[UTC][!u-ca=iso8601]", "with ! and time zone"],
+ ["2000-05-02T15:23[u-ca=iso8601][u-ca=discord]", "second annotation ignored"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.inLeapYear(arg);
+
+ assert.sameValue(
+ result,
+ true,
+ `calendar annotation (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string-critical-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string-critical-unknown-annotation.js
new file mode 100644
index 0000000000..d7a4e32644
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string-critical-unknown-annotation.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.inleapyear
+description: Unknown annotations with critical flag are rejected
+features: [Temporal]
+---*/
+
+const invalidStrings = [
+ "1970-01-01[!foo=bar]",
+ "1970-01-01T00:00[!foo=bar]",
+ "1970-01-01T00:00[UTC][!foo=bar]",
+ "1970-01-01T00:00[u-ca=iso8601][!foo=bar]",
+ "1970-01-01T00:00[UTC][!foo=bar][u-ca=iso8601]",
+ "1970-01-01T00:00[foo=bar][!_foo-bar0=Dont-Ignore-This-99999999999]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.inLeapYear(arg),
+ `reject unknown annotation with critical flag: ${arg}`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string-date-with-utc-offset.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string-date-with-utc-offset.js
new file mode 100644
index 0000000000..4d68cef862
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string-date-with-utc-offset.js
@@ -0,0 +1,48 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.inleapyear
+description: UTC offset not valid with format that does not include a time
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const validStrings = [
+ "2000-05-02T00+00:00",
+ "2000-05-02T00+00:00[UTC]",
+ "2000-05-02T00+00:00[!UTC]",
+ "2000-05-02T00-02:30[America/St_Johns]",
+];
+
+for (const arg of validStrings) {
+ const result = instance.inLeapYear(arg);
+
+ assert.sameValue(
+ result,
+ true,
+ `"${arg}" is a valid UTC offset with time for PlainDate`
+ );
+}
+
+const invalidStrings = [
+ "2022-09-15Z",
+ "2022-09-15Z[UTC]",
+ "2022-09-15Z[Europe/Vienna]",
+ "2022-09-15+00:00",
+ "2022-09-15+00:00[UTC]",
+ "2022-09-15-02:30",
+ "2022-09-15-02:30[America/St_Johns]",
+];
+
+for (const arg of invalidStrings) {
+ assert.throws(
+ RangeError,
+ () => instance.inLeapYear(arg),
+ `"${arg}" UTC offset without time is not valid for PlainDate`
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string-invalid.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string-invalid.js
new file mode 100644
index 0000000000..51f36ee0cb
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string-invalid.js
@@ -0,0 +1,64 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.inleapyear
+description: >
+ RangeError thrown if an invalid ISO string (or syntactically valid ISO string
+ that is not supported) is used as a PlainDate
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ // invalid ISO strings:
+ "",
+ "invalid iso8601",
+ "2020-01-00",
+ "2020-01-32",
+ "2020-02-30",
+ "2021-02-29",
+ "2020-00-01",
+ "2020-13-01",
+ "2020-01-01T",
+ "2020-01-01T25:00:00",
+ "2020-01-01T01:60:00",
+ "2020-01-01T01:60:61",
+ "2020-01-01junk",
+ "2020-01-01T00:00:00junk",
+ "2020-01-01T00:00:00+00:00junk",
+ "2020-01-01T00:00:00+00:00[UTC]junk",
+ "2020-01-01T00:00:00+00:00[UTC][u-ca=iso8601]junk",
+ "02020-01-01",
+ "2020-001-01",
+ "2020-01-001",
+ "2020-01-01T001",
+ "2020-01-01T01:001",
+ "2020-01-01T01:01:001",
+ // valid, but forms not supported in Temporal:
+ "2020-W01-1",
+ "2020-001",
+ "+0002020-01-01",
+ // valid, but this calendar must not exist:
+ "2020-01-01[u-ca=notexist]",
+ // may be valid in other contexts, but insufficient information for PlainDate:
+ "2020-01",
+ "+002020-01",
+ "01-01",
+ "2020-W01",
+ "P1Y",
+ "-P12Y",
+ // valid, but outside the supported range:
+ "-999999-01-01",
+ "+999999-01-01",
+];
+const instance = new Temporal.Calendar("iso8601");
+for (const arg of invalidStrings) {
+ assert.throws(
+ RangeError,
+ () => instance.inLeapYear(arg),
+ `"${arg}" should not be a valid ISO string for a PlainDate`
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string-multiple-calendar.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string-multiple-calendar.js
new file mode 100644
index 0000000000..bb3468f3de
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string-multiple-calendar.js
@@ -0,0 +1,32 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.inleapyear
+description: >
+ More than one calendar annotation is not syntactical if any have the criical
+ flag
+features: [Temporal]
+---*/
+
+const invalidStrings = [
+ "1970-01-01[u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01[!u-ca=iso8601][u-ca=iso8601]",
+ "1970-01-01[UTC][u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01[u-ca=iso8601][foo=bar][!u-ca=iso8601]",
+ "1970-01-01T00:00[u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01T00:00[!u-ca=iso8601][u-ca=iso8601]",
+ "1970-01-01T00:00[UTC][u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01T00:00[u-ca=iso8601][foo=bar][!u-ca=iso8601]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.inLeapYear(arg),
+ `reject more than one calendar annotation if any critical: ${arg}`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string-multiple-time-zone.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string-multiple-time-zone.js
new file mode 100644
index 0000000000..ae1f291355
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string-multiple-time-zone.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.inleapyear
+description: More than one time zone annotation is not syntactical
+features: [Temporal]
+---*/
+
+const invalidStrings = [
+ "1970-01-01[UTC][UTC]",
+ "1970-01-01T00:00[UTC][UTC]",
+ "1970-01-01T00:00[!UTC][UTC]",
+ "1970-01-01T00:00[UTC][!UTC]",
+ "1970-01-01T00:00[UTC][u-ca=iso8601][UTC]",
+ "1970-01-01T00:00[UTC][foo=bar][UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.inLeapYear(arg),
+ `reject more than one time zone annotation: ${arg}`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string-time-separators.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string-time-separators.js
new file mode 100644
index 0000000000..be8ab2a244
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string-time-separators.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.inleapyear
+description: Time separator in string argument can vary
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02T15:23", "uppercase T"],
+ ["2000-05-02t15:23", "lowercase T"],
+ ["2000-05-02 15:23", "space between date and time"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.inLeapYear(arg);
+
+ assert.sameValue(
+ result,
+ true,
+ `variant time separators (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string-time-zone-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string-time-zone-annotation.js
new file mode 100644
index 0000000000..0c410681b1
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string-time-zone-annotation.js
@@ -0,0 +1,38 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.inleapyear
+description: Various forms of time zone annotation; critical flag has no effect
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02[Asia/Kolkata]", "named, with no time"],
+ ["2000-05-02[!Europe/Vienna]", "named, with ! and no time"],
+ ["2000-05-02[+00:00]", "numeric, with no time"],
+ ["2000-05-02[!-02:30]", "numeric, with ! and no time"],
+ ["2000-05-02T15:23[America/Sao_Paulo]", "named, with no offset"],
+ ["2000-05-02T15:23[!Asia/Tokyo]", "named, with ! and no offset"],
+ ["2000-05-02T15:23[-02:30]", "numeric, with no offset"],
+ ["2000-05-02T15:23[!+00:00]", "numeric, with ! and no offset"],
+ ["2000-05-02T15:23+00:00[America/New_York]", "named, with offset"],
+ ["2000-05-02T15:23+00:00[!UTC]", "named, with offset and !"],
+ ["2000-05-02T15:23+00:00[+01:00]", "numeric, with offset"],
+ ["2000-05-02T15:23+00:00[!-08:00]", "numeric, with offset and !"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.inLeapYear(arg);
+
+ assert.sameValue(
+ result,
+ true,
+ `time zone annotation (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string-unknown-annotation.js
new file mode 100644
index 0000000000..6e73f60c4f
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string-unknown-annotation.js
@@ -0,0 +1,32 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.inleapyear
+description: Various forms of unknown annotation
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02[foo=bar]", "without time"],
+ ["2000-05-02T15:23[foo=bar]", "alone"],
+ ["2000-05-02T15:23[UTC][foo=bar]", "with time zone"],
+ ["2000-05-02T15:23[u-ca=iso8601][foo=bar]", "with calendar"],
+ ["2000-05-02T15:23[UTC][foo=bar][u-ca=iso8601]", "with time zone and calendar"],
+ ["2000-05-02T15:23[foo=bar][_foo-bar0=Ignore-This-999999999999]", "with another unknown annotation"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.inLeapYear(arg);
+
+ assert.sameValue(
+ result,
+ true,
+ `unknown annotation (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string-with-utc-designator.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string-with-utc-designator.js
new file mode 100644
index 0000000000..6a1b8e81ee
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string-with-utc-designator.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.inleapyear
+description: RangeError thrown if a string with UTC designator is used as a PlainDate
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ "2019-10-01T09:00:00Z",
+ "2019-10-01T09:00:00Z[UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.inLeapYear(arg),
+ "String with UTC designator should not be valid as a PlainDate"
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string.js
new file mode 100644
index 0000000000..386d77fc36
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.inleapyear
+description: An ISO 8601 date string should be converted as input
+info: |
+ 4. If Type(temporalDateLike) is not Object or temporalDateLike does not have an [[InitializedTemporalDate]] or [[InitializedTemporalYearMonth]] internal slot, then
+ a. Set temporalDateLike to ? ToTemporalDate(temporalDateLike).
+ 5. Return ! IsISOLeapYear(temporalDateLike.[[ISOYear]]).
+features: [Temporal]
+---*/
+
+const cal = new Temporal.Calendar("iso8601");
+
+assert.sameValue(cal.inLeapYear("2019-03-18"), false);
+assert.sameValue(cal.inLeapYear("2020-03-18"), true);
+
+assert.sameValue(cal.inLeapYear("+002023-03-18"), false);
+assert.sameValue(cal.inLeapYear("+002024-03-18"), true);
+
+assert.sameValue(cal.inLeapYear("2019-03-18T13:00:00+00:00[UTC]"), false);
+assert.sameValue(cal.inLeapYear("2020-12-31T23:59:59+00:00[UTC]"), true);
+
+assert.sameValue(cal.inLeapYear("+002023-03-18T13:00:00+00:00[UTC]"), false);
+assert.sameValue(cal.inLeapYear("+002024-03-18T13:00:00+00:00[UTC]"), true);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-wrong-type.js
new file mode 100644
index 0000000000..62c7f9da78
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-wrong-type.js
@@ -0,0 +1,43 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.inleapyear
+description: >
+ Appropriate error thrown when argument cannot be converted to a valid string
+ or property bag for PlainDate
+features: [BigInt, Symbol, Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const primitiveTests = [
+ [undefined, "undefined"],
+ [null, "null"],
+ [true, "boolean"],
+ ["", "empty string"],
+ [1, "number that doesn't convert to a valid ISO string"],
+ [1n, "bigint"],
+];
+
+for (const [arg, description] of primitiveTests) {
+ assert.throws(
+ typeof arg === 'string' ? RangeError : TypeError,
+ () => instance.inLeapYear(arg),
+ `${description} does not convert to a valid ISO string`
+ );
+}
+
+const typeErrorTests = [
+ [Symbol(), "symbol"],
+ [{}, "plain object"],
+ [Temporal.PlainDate, "Temporal.PlainDate, object"],
+ [Temporal.PlainDate.prototype, "Temporal.PlainDate.prototype, object"],
+];
+
+for (const [arg, description] of typeErrorTests) {
+ assert.throws(TypeError, () => instance.inLeapYear(arg), `${description} is not a valid property bag and does not convert to a string`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-zoneddatetime-convert.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-zoneddatetime-convert.js
new file mode 100644
index 0000000000..0eaaa5648a
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-zoneddatetime-convert.js
@@ -0,0 +1,22 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.inleapyear
+description: An exception from TimeZone#getOffsetNanosecondsFor() is propagated.
+features: [Temporal]
+---*/
+
+class TZ extends Temporal.TimeZone {
+ constructor() { super("UTC") }
+ getOffsetNanosecondsFor() { throw new Test262Error() }
+}
+
+const tz = new TZ();
+const arg = new Temporal.ZonedDateTime(0n, tz);
+const instance = new Temporal.Calendar("iso8601");
+
+assert.throws(Test262Error, () => instance.inLeapYear(arg));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-zoneddatetime-slots.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-zoneddatetime-slots.js
new file mode 100644
index 0000000000..deb0f55d75
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-zoneddatetime-slots.js
@@ -0,0 +1,40 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.inleapyear
+description: Getters are not called when converting a ZonedDateTime to a PlainDate.
+includes: [compareArray.js]
+features: [Temporal]
+---*/
+
+const actual = [];
+const prototypeDescrs = Object.getOwnPropertyDescriptors(Temporal.ZonedDateTime.prototype);
+const getters = ["year", "month", "monthCode", "day", "hour", "minute", "second", "millisecond", "microsecond", "nanosecond", "calendar"];
+
+for (const property of getters) {
+ Object.defineProperty(Temporal.ZonedDateTime.prototype, property, {
+ get() {
+ actual.push(`get ${property}`);
+ const value = prototypeDescrs[property].get.call(this);
+ return {
+ toString() {
+ actual.push(`toString ${property}`);
+ return value.toString();
+ },
+ valueOf() {
+ actual.push(`valueOf ${property}`);
+ return value;
+ },
+ };
+ },
+ });
+}
+
+const arg = new Temporal.ZonedDateTime(0n, "UTC");
+const instance = new Temporal.Calendar("iso8601");
+instance.inLeapYear(arg);
+assert.compareArray(actual, []);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js
new file mode 100644
index 0000000000..855ce0b0a5
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.inleapyear
+description: RangeError thrown if time zone reports an offset that is not an integer number of nanoseconds
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+[3600_000_000_000.5, NaN, -Infinity, Infinity].forEach((wrongOffset) => {
+ const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset);
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ assert.throws(RangeError, () => calendar.inLeapYear(datetime));
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js
new file mode 100644
index 0000000000..2133bdff72
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.inleapyear
+description: TypeError thrown if timeZone.getOffsetNanosecondsFor is not callable
+features: [BigInt, Symbol, Temporal, arrow-function]
+---*/
+
+[undefined, null, true, Math.PI, 'string', Symbol('sym'), 42n, {}].forEach((notCallable) => {
+ const timeZone = new Temporal.TimeZone("UTC");
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ timeZone.getOffsetNanosecondsFor = notCallable;
+ assert.throws(
+ TypeError,
+ () => calendar.inLeapYear(datetime),
+ `Uncallable ${notCallable === null ? 'null' : typeof notCallable} getOffsetNanosecondsFor should throw TypeError`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js
new file mode 100644
index 0000000000..073dfc3f0f
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.inleapyear
+description: RangeError thrown if time zone reports an offset that is out of range
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+[-86400_000_000_000, 86400_000_000_000].forEach((wrongOffset) => {
+ const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset);
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ assert.throws(RangeError, () => calendar.inLeapYear(datetime));
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js
new file mode 100644
index 0000000000..8156a9a9d2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.inleapyear
+description: TypeError thrown if time zone reports an offset that is not a Number
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+[
+ undefined,
+ null,
+ true,
+ "+01:00",
+ Symbol(),
+ 3600_000_000_000n,
+ {},
+ { valueOf() { return 3600_000_000_000; } },
+].forEach((wrongOffset) => {
+ const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset);
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ assert.throws(TypeError, () => calendar.inLeapYear(datetime));
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/basic.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/basic.js
new file mode 100644
index 0000000000..0629f27bb4
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/basic.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.inleapyear
+description: Basic tests for inLeapYear().
+features: [Temporal]
+---*/
+
+const iso = Temporal.Calendar.from("iso8601");
+let res = false;
+
+assert.sameValue(iso.inLeapYear(new Temporal.PlainDate(1994, 11, 5)), res, "PlainDate");
+assert.sameValue(iso.inLeapYear(new Temporal.PlainDateTime(1994, 11, 5, 8, 15, 30)), res, "PlainDateTime");
+assert.sameValue(iso.inLeapYear(new Temporal.PlainYearMonth(1994, 11)), res, "PlainYearMonth");
+assert.sameValue(iso.inLeapYear({ year: 1994, month: 11, day: 5 }), res, "property bag");
+assert.sameValue(iso.inLeapYear("1994-11-05"), res, "string");
+
+res = true;
+assert.sameValue(iso.inLeapYear(new Temporal.PlainDate(1996, 7, 15)), res, "PlainDate in leap year");
+assert.sameValue(iso.inLeapYear(new Temporal.PlainDateTime(1996, 7, 15, 5, 30, 13)), res, "PlainDateTime in leap year");
+assert.sameValue(iso.inLeapYear(new Temporal.PlainYearMonth(1996, 7)), res, "PlainYearMonth in leap year");
+assert.sameValue(iso.inLeapYear({ year: 1996, month: 7, day: 15 }), res, "property bag in leap year");
+assert.sameValue(iso.inLeapYear("1996-07-15"), res, "string in leap year");
+
+assert.throws(TypeError, () => iso.inLeapYear({ year: 2000 }), "property bag with missing properties");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/branding.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/branding.js
new file mode 100644
index 0000000000..a093d181e8
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/branding.js
@@ -0,0 +1,27 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.inleapyear
+description: Throw a TypeError if the receiver is invalid
+features: [Symbol, Temporal]
+---*/
+
+const inLeapYear = Temporal.Calendar.prototype.inLeapYear;
+
+assert.sameValue(typeof inLeapYear, "function");
+
+const args = [new Temporal.PlainDate(2021, 3, 4)];
+
+assert.throws(TypeError, () => inLeapYear.apply(undefined, args), "undefined");
+assert.throws(TypeError, () => inLeapYear.apply(null, args), "null");
+assert.throws(TypeError, () => inLeapYear.apply(true, args), "true");
+assert.throws(TypeError, () => inLeapYear.apply("", args), "empty string");
+assert.throws(TypeError, () => inLeapYear.apply(Symbol(), args), "symbol");
+assert.throws(TypeError, () => inLeapYear.apply(1, args), "1");
+assert.throws(TypeError, () => inLeapYear.apply({}, args), "plain object");
+assert.throws(TypeError, () => inLeapYear.apply(Temporal.Calendar, args), "Temporal.Calendar");
+assert.throws(TypeError, () => inLeapYear.apply(Temporal.Calendar.prototype, args), "Temporal.Calendar.prototype");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/browser.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/browser.js
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/builtin.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/builtin.js
new file mode 100644
index 0000000000..7af66d6a7b
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/builtin.js
@@ -0,0 +1,36 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.inleapyear
+description: >
+ Tests that Temporal.Calendar.prototype.inLeapYear
+ meets the requirements for built-in objects defined by the
+ introduction of chapter 17 of the ECMAScript Language Specification.
+info: |
+ Built-in functions that are not constructors do not have a "prototype" property unless
+ otherwise specified in the description of a particular function.
+
+ Unless specified otherwise, a built-in object that is callable as a function is a built-in
+ function object with the characteristics described in 10.3. Unless specified otherwise, the
+ [[Extensible]] internal slot of a built-in object initially has the value true.
+
+ Unless otherwise specified every built-in function and every built-in constructor has the
+ Function prototype object [...] as the value of its [[Prototype]] internal slot.
+features: [Temporal]
+---*/
+
+assert.sameValue(Object.isExtensible(Temporal.Calendar.prototype.inLeapYear),
+ true, "Built-in objects must be extensible.");
+
+assert.sameValue(Object.prototype.toString.call(Temporal.Calendar.prototype.inLeapYear),
+ "[object Function]", "Object.prototype.toString");
+
+assert.sameValue(Object.getPrototypeOf(Temporal.Calendar.prototype.inLeapYear),
+ Function.prototype, "prototype");
+
+assert.sameValue(Temporal.Calendar.prototype.inLeapYear.hasOwnProperty("prototype"),
+ false, "prototype property");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/calendar-datefromfields-called-with-options-undefined.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/calendar-datefromfields-called-with-options-undefined.js
new file mode 100644
index 0000000000..d5296d2717
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/calendar-datefromfields-called-with-options-undefined.js
@@ -0,0 +1,18 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.inleapyear
+description: >
+ Calendar.dateFromFields method is called with undefined as the options value
+ when call originates internally
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions();
+calendar.inLeapYear({ year: 2000, month: 5, day: 3, calendar });
+assert.sameValue(calendar.dateFromFieldsCallCount, 1);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/calendar-fields-iterable.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/calendar-fields-iterable.js
new file mode 100644
index 0000000000..d04651f126
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/calendar-fields-iterable.js
@@ -0,0 +1,37 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.inleapyear
+description: Verify the result of calendar.fields() is treated correctly.
+info: |
+ sec-temporal.calendar.prototype.inleapyear step 4:
+ 4. Let _year_ be ? ISOYear(_dateOrDateTime_).
+ sec-temporal-isoyear step 1.a:
+ a. Set _dateOrDateTime_ to ? ToTemporalDate(_dateOrDateTime_).
+ sec-temporal-totemporaldate step 2.c:
+ c. Let _fieldNames_ be ? CalendarFields(_calendar_, « *"day"*, *"month"*, *"monthCode"*, *"year"* »).
+ sec-temporal-calendarfields step 4:
+ 4. Let _result_ be ? IterableToListOfType(_fieldsArray_, « String »).
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const expected = [
+ "day",
+ "month",
+ "monthCode",
+ "year",
+];
+
+const calendar1 = TemporalHelpers.calendarFieldsIterable();
+const calendar2 = TemporalHelpers.calendarFieldsIterable();
+calendar1.inLeapYear({ year: 2000, month: 5, day: 2, calendar: calendar2 });
+
+assert.sameValue(calendar1.fieldsCallCount, 0, "fields() method not called");
+assert.sameValue(calendar2.fieldsCallCount, 1, "fields() method called once");
+assert.compareArray(calendar2.fieldsCalledWith[0], expected, "fields() method called with correct args");
+assert(calendar2.iteratorExhausted[0], "iterated through the whole iterable");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/calendar-temporal-object.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/calendar-temporal-object.js
new file mode 100644
index 0000000000..af40ed70f8
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/calendar-temporal-object.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.inleapyear
+description: Fast path for converting other Temporal objects to Temporal.Calendar by reading internal slots
+info: |
+ sec-temporal.calendar.prototype.inleapyear step 4:
+ 4. Let _year_ be ? ISOYear(_dateOrDateTime_).
+ sec-temporal-totemporaldate step 2.c:
+ c. Let _calendar_ be ? GetTemporalCalendarWithISODefault(_item_).
+ sec-temporal-gettemporalcalendarwithisodefault step 2:
+ 2. Return ? ToTemporalCalendarWithISODefault(_calendar_).
+ sec-temporal-totemporalcalendarwithisodefault step 2:
+ 3. Return ? ToTemporalCalendar(_temporalCalendarLike_).
+ sec-temporal-totemporalcalendar step 1.a:
+ a. If _temporalCalendarLike_ has an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]], [[InitializedTemporalMonthDay]], [[InitializedTemporalYearMonth]], or [[InitializedTemporalZonedDateTime]] internal slot, then
+ i. Return _temporalCalendarLike_.[[Calendar]].
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+TemporalHelpers.checkToTemporalCalendarFastPath((temporalObject) => {
+ const calendar = new Temporal.Calendar("iso8601");
+ calendar.inLeapYear({ year: 2000, month: 5, day: 2, calendar: temporalObject });
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/infinity-throws-rangeerror.js
new file mode 100644
index 0000000000..3800fd60d0
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/infinity-throws-rangeerror.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: Throws if any value in the property bag is Infinity or -Infinity
+esid: sec-temporal.calendar.prototype.inleapyear
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+const base = { year: 2000, month: 5, day: 2 };
+
+[Infinity, -Infinity].forEach((inf) => {
+ ["year", "month", "day"].forEach((prop) => {
+ assert.throws(RangeError, () => instance.inLeapYear({ ...base, [prop]: inf }), `${prop} property cannot be ${inf}`);
+
+ const calls = [];
+ const obj = TemporalHelpers.toPrimitiveObserver(calls, inf, prop);
+ assert.throws(RangeError, () => instance.inLeapYear({ ...base, [prop]: obj }));
+ assert.compareArray(calls, [`get ${prop}.valueOf`, `call ${prop}.valueOf`], "it fails after fetching the primitive value");
+ });
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/length.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/length.js
new file mode 100644
index 0000000000..c14994d608
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/length.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2020 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.inleapyear
+description: Temporal.Calendar.prototype.inLeapYear.length is 1
+info: |
+ Every built-in function object, including constructors, has a "length" property whose value is
+ an integer. Unless otherwise specified, this value is equal to the largest number of named
+ arguments shown in the subclause headings for the function description. Optional parameters
+ (which are indicated with brackets: [ ]) or rest parameters (which are shown using the form
+ «...name») are not included in the default argument count.
+
+ Unless otherwise specified, the "length" property of a built-in function object has the
+ attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+verifyProperty(Temporal.Calendar.prototype.inLeapYear, "length", {
+ value: 1,
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/name.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/name.js
new file mode 100644
index 0000000000..0243320bd6
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/name.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.inleapyear
+description: Temporal.Calendar.prototype.inLeapYear.name is "inLeapYear".
+info: |
+ Every built-in function object, including constructors, that is not identified as an anonymous
+ function has a "name" property whose value is a String. Unless otherwise specified, this value
+ is the name that is given to the function in this specification.
+
+ Unless otherwise specified, the "name" property of a built-in function object, if it exists,
+ has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+verifyProperty(Temporal.Calendar.prototype.inLeapYear, "name", {
+ value: "inLeapYear",
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/not-a-constructor.js
new file mode 100644
index 0000000000..5e1ce16eef
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/not-a-constructor.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.inleapyear
+description: >
+ Temporal.Calendar.prototype.inLeapYear does not implement [[Construct]], is not new-able
+info: |
+ Built-in function objects that are not identified as constructors do not implement the
+ [[Construct]] internal method unless otherwise specified in the description of a particular
+ function.
+includes: [isConstructor.js]
+features: [Reflect.construct, Temporal]
+---*/
+
+assert.throws(TypeError, () => {
+ new Temporal.Calendar.prototype.inLeapYear();
+}, "Calling as constructor");
+
+assert.sameValue(isConstructor(Temporal.Calendar.prototype.inLeapYear), false,
+ "isConstructor(Temporal.Calendar.prototype.inLeapYear)");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/prop-desc.js
new file mode 100644
index 0000000000..43017e7fb9
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/prop-desc.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.inleapyear
+description: The "inLeapYear" property of Temporal.Calendar.prototype
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+assert.sameValue(
+ typeof Temporal.Calendar.prototype.inLeapYear,
+ "function",
+ "`typeof Calendar.prototype.inLeapYear` is `function`"
+);
+
+verifyProperty(Temporal.Calendar.prototype, "inLeapYear", {
+ writable: true,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/shell.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/shell.js
new file mode 100644
index 0000000000..eda1477282
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/shell.js
@@ -0,0 +1,24 @@
+// GENERATED, DO NOT EDIT
+// file: isConstructor.js
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: |
+ Test if a given function is a constructor function.
+defines: [isConstructor]
+features: [Reflect.construct]
+---*/
+
+function isConstructor(f) {
+ if (typeof f !== "function") {
+ throw new Test262Error("isConstructor invoked with a non-function value");
+ }
+
+ try {
+ Reflect.construct(function(){}, [], f);
+ } catch (e) {
+ return false;
+ }
+ return true;
+}
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/year-zero.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/year-zero.js
new file mode 100644
index 0000000000..26f32ed16a
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/inLeapYear/year-zero.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.inleapyear
+description: Negative zero, as an extended year, is rejected
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ "-000000-10-31",
+ "-000000-10-31T00:45",
+ "-000000-10-31T00:45+01:00",
+ "-000000-10-31T00:45+00:00[UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.inLeapYear(arg),
+ "reject minus zero as extended year"
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/arguments-empty-object.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/arguments-empty-object.js
new file mode 100644
index 0000000000..a5d437c195
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/arguments-empty-object.js
@@ -0,0 +1,35 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.mergefields
+description: Either argument being an empty object should result in a copy of the other object
+includes: [compareArray.js]
+features: [Temporal]
+---*/
+
+const calendar = new Temporal.Calendar("iso8601");
+
+let calls = 0;
+const yearObserver = {
+ get year() {
+ calls++;
+ return 2021;
+ }
+};
+
+const result1 = calendar.mergeFields(yearObserver, {});
+assert.sameValue(calls, 1, "property copied");
+assert.compareArray(Object.keys(result1), ["year"]);
+assert.sameValue(result1.year, 2021);
+assert.sameValue(calls, 1, "result has a data property");
+
+calls = 0;
+const result2 = calendar.mergeFields({}, yearObserver);
+assert.sameValue(calls, 1, "property copied");
+assert.compareArray(Object.keys(result2), ["year"]);
+assert.sameValue(result2.year, 2021);
+assert.sameValue(calls, 1, "result has a data property");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/arguments-not-object.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/arguments-not-object.js
new file mode 100644
index 0000000000..3355b631d9
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/arguments-not-object.js
@@ -0,0 +1,43 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.mergefields
+description: Non-object arguments are converted with ToObject and merge their [[OwnPropertyKeys]] onto a new object
+includes: [compareArray.js]
+features: [Temporal]
+---*/
+
+const calendar = new Temporal.Calendar("iso8601");
+
+assert.throws(TypeError, () => calendar.mergeFields(undefined, {}));
+assert.throws(TypeError, () => calendar.mergeFields({}, undefined));
+
+assert.throws(TypeError, () => calendar.mergeFields(null, {}));
+assert.throws(TypeError, () => calendar.mergeFields({}, null));
+
+const boolResult = calendar.mergeFields(true, false);
+assert.compareArray(Object.keys(boolResult), [], "Boolean objects have no own property keys");
+assert.sameValue(Object.getPrototypeOf(boolResult), null, "null-prototype object returned");
+
+const numResult = calendar.mergeFields(3, 4);
+assert.compareArray(Object.keys(numResult), [], "Number objects have no own property keys");
+assert.sameValue(Object.getPrototypeOf(boolResult), null, "null-prototype object returned");
+
+const strResult = calendar.mergeFields("abc", "de");
+assert.compareArray(Object.keys(strResult), ["0", "1", "2"], "String objects have integer indices as own property keys");
+assert.sameValue(strResult["0"], "d");
+assert.sameValue(strResult["1"], "e");
+assert.sameValue(strResult["2"], "c");
+assert.sameValue(Object.getPrototypeOf(boolResult), null, "null-prototype object returned");
+
+const symResult = calendar.mergeFields(Symbol("foo"), Symbol("bar"));
+assert.compareArray(Object.keys(symResult), [], "Symbol objects have no own property keys");
+assert.sameValue(Object.getPrototypeOf(symResult), null, "null-prototype object returned");
+
+const bigintResult = calendar.mergeFields(3n, 4n);
+assert.compareArray(Object.keys(bigintResult), [], "BigInt objects have no own property keys");
+assert.sameValue(Object.getPrototypeOf(bigintResult), null, "null-prototype object returned");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/basic.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/basic.js
new file mode 100644
index 0000000000..2a9d6abacd
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/basic.js
@@ -0,0 +1,36 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// Copyright (C) 2022 Igalia S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.mergefields
+description: >
+ Temporal.Calendar.prototype.mergeFields will merge own data properties on its
+ arguments
+info: |
+ 1. Let calendar be the this value.
+ 2. Perform ? RequireInternalSlot(calendar, [[InitializedTemporalCalendar]]).
+ 3. Assert: calendar.[[Identifier]] is "iso8601".
+ 4. Set fields to ? ToObject(fields).
+ 5. Set additionalFields to ? ToObject(additionalFields).
+ 6. Return ? DefaultMergeFields(fields, additionalFields).
+features: [Temporal]
+includes: [deepEqual.js]
+---*/
+
+const cal = new Temporal.Calendar("iso8601");
+
+assert.deepEqual(
+ cal.mergeFields({ a: 1, b: 2 }, { c: 3, d: 4 }),
+ { a: 1, b: 2, c: 3, d: 4 },
+ "properties are merged"
+);
+
+assert.deepEqual(
+ cal.mergeFields({ a: 1, b: 2 }, { b: 3, c: 4 }),
+ { a: 1, b: 3, c: 4 },
+ "property in additionalFields should overwrite one in fields"
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/branding.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/branding.js
new file mode 100644
index 0000000000..9fc1451238
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/branding.js
@@ -0,0 +1,27 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.mergefields
+description: Throw a TypeError if the receiver is invalid
+features: [Symbol, Temporal]
+---*/
+
+const mergeFields = Temporal.Calendar.prototype.mergeFields;
+
+assert.sameValue(typeof mergeFields, "function");
+
+const args = [{}, {}];
+
+assert.throws(TypeError, () => mergeFields.apply(undefined, args), "undefined");
+assert.throws(TypeError, () => mergeFields.apply(null, args), "null");
+assert.throws(TypeError, () => mergeFields.apply(true, args), "true");
+assert.throws(TypeError, () => mergeFields.apply("", args), "empty string");
+assert.throws(TypeError, () => mergeFields.apply(Symbol(), args), "symbol");
+assert.throws(TypeError, () => mergeFields.apply(1, args), "1");
+assert.throws(TypeError, () => mergeFields.apply({}, args), "plain object");
+assert.throws(TypeError, () => mergeFields.apply(Temporal.Calendar, args), "Temporal.Calendar");
+assert.throws(TypeError, () => mergeFields.apply(Temporal.Calendar.prototype, args), "Temporal.Calendar.prototype");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/browser.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/browser.js
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/builtin.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/builtin.js
new file mode 100644
index 0000000000..6f7cee257c
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/builtin.js
@@ -0,0 +1,36 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.mergefields
+description: >
+ Tests that Temporal.Calendar.prototype.mergeFields
+ meets the requirements for built-in objects defined by the
+ introduction of chapter 17 of the ECMAScript Language Specification.
+info: |
+ Built-in functions that are not constructors do not have a "prototype" property unless
+ otherwise specified in the description of a particular function.
+
+ Unless specified otherwise, a built-in object that is callable as a function is a built-in
+ function object with the characteristics described in 10.3. Unless specified otherwise, the
+ [[Extensible]] internal slot of a built-in object initially has the value true.
+
+ Unless otherwise specified every built-in function and every built-in constructor has the
+ Function prototype object [...] as the value of its [[Prototype]] internal slot.
+features: [Temporal]
+---*/
+
+assert.sameValue(Object.isExtensible(Temporal.Calendar.prototype.mergeFields),
+ true, "Built-in objects must be extensible.");
+
+assert.sameValue(Object.prototype.toString.call(Temporal.Calendar.prototype.mergeFields),
+ "[object Function]", "Object.prototype.toString");
+
+assert.sameValue(Object.getPrototypeOf(Temporal.Calendar.prototype.mergeFields),
+ Function.prototype, "prototype");
+
+assert.sameValue(Temporal.Calendar.prototype.mergeFields.hasOwnProperty("prototype"),
+ false, "prototype property");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/iso8601-calendar-month-monthCode.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/iso8601-calendar-month-monthCode.js
new file mode 100644
index 0000000000..d223e63931
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/iso8601-calendar-month-monthCode.js
@@ -0,0 +1,102 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.mergefields
+description: >
+ The default mergeFields algorithm from the ISO 8601 calendar should correctly
+ merge the month and monthCode properties
+info: |
+ 1. Let calendar be the this value.
+ 2. Perform ? RequireInternalSlot(calendar, [[InitializedTemporalCalendar]]).
+ 3. Assert: calendar.[[Identifier]] is "iso8601".
+ 4. Set fields to ? ToObject(fields).
+ 5. Set additionalFields to ? ToObject(additionalFields).
+ 6. Return ? DefaultMergeFields(fields, additionalFields).
+features: [Temporal]
+includes: [deepEqual.js]
+---*/
+
+const cal = new Temporal.Calendar("iso8601");
+
+assert.deepEqual(
+ cal.mergeFields({ a: 1, b: 2, month: 7 }, { b: 3, c: 4 }),
+ { a: 1, b: 3, c: 4, month: 7 },
+ "month is copied from fields"
+);
+assert.deepEqual(
+ cal.mergeFields({ a: 1, b: 2, monthCode: "M08" }, { b: 3, c: 4 }),
+ { a: 1, b: 3, c: 4, monthCode: "M08" },
+ "monthCode is copied from fields"
+);
+assert.deepEqual(
+ cal.mergeFields({ a: 1, b: 2, month: 7, monthCode: "M08" }, { b: 3, c: 4 }),
+ { a: 1, b: 3, c: 4, month: 7, monthCode: "M08" },
+ "both month and monthCode are copied from fields, no validation is performed"
+);
+
+assert.deepEqual(
+ cal.mergeFields({ a: 1, b: 2 }, { b: 3, c: 4, month: 5 }),
+ { a: 1, b: 3, c: 4, month: 5 },
+ "month is copied from additionalFields"
+);
+assert.deepEqual(
+ cal.mergeFields({ a: 1, b: 2 }, { b: 3, c: 4, monthCode: "M06" }),
+ { a: 1, b: 3, c: 4, monthCode: "M06" },
+ "monthCode is copied from additionalFields"
+);
+assert.deepEqual(
+ cal.mergeFields({ a: 1, b: 2 }, { b: 3, c: 4, month: 5, monthCode: "M06" }),
+ { a: 1, b: 3, c: 4, month: 5, monthCode: "M06" },
+ "both month and monthCode are copied from additionalFields, no validation is performed"
+);
+
+assert.deepEqual(
+ cal.mergeFields({ a: 1, b: 2, month: 7 }, { b: 3, c: 4, month: 5 }),
+ { a: 1, b: 3, c: 4, month: 5 },
+ "month from additionalFields overrides month from fields"
+);
+assert.deepEqual(
+ cal.mergeFields({ a: 1, b: 2, monthCode: "M07" }, { b: 3, c: 4, monthCode: "M05" }),
+ { a: 1, b: 3, c: 4, monthCode: "M05" },
+ "monthCode from additionalFields overrides monthCode from fields"
+);
+assert.deepEqual(
+ cal.mergeFields({ a: 1, b: 2, monthCode: "M07" }, { b: 3, c: 4, month: 6 }),
+ { a: 1, b: 3, c: 4, month: 6 },
+ "month's presence on additionalFields blocks monthCode from fields"
+);
+assert.deepEqual(
+ cal.mergeFields({ a: 1, b: 2, month: 7 }, { b: 3, c: 4, monthCode: "M06" }),
+ { a: 1, b: 3, c: 4, monthCode: "M06"},
+ "monthCode's presence on additionalFields blocks month from fields"
+);
+assert.deepEqual(
+ cal.mergeFields({ a: 1, b: 2, month: 7, monthCode: "M08" },{ b: 3, c: 4, month: 5 }),
+ { a: 1, b: 3, c: 4, month: 5 },
+ "month's presence on additionalFields blocks both month and monthCode from fields"
+);
+assert.deepEqual(
+ cal.mergeFields({ a: 1, b: 2, month: 7, monthCode: "M08" }, { b: 3, c: 4, monthCode: "M06" }),
+ { a: 1, b: 3, c: 4, monthCode: "M06" },
+ "monthCode's presence on additionalFields blocks both month and monthCode from fields"
+);
+
+assert.deepEqual(
+ cal.mergeFields({ a: 1, b: 2, month: 7 }, { b: 3, c: 4, month: 5, monthCode: "M06" }),
+ { a: 1, b: 3, c: 4, month: 5, monthCode: "M06" },
+ "both month and monthCode are copied from additionalFields even when fields has month"
+);
+assert.deepEqual(
+ cal.mergeFields({ a: 1, b: 2, monthCode: "M07" }, { b: 3, c: 4, month: 5, monthCode: "M06" }),
+ { a: 1, b: 3, c: 4, month: 5, monthCode: "M06" },
+ "both month and monthCode are copied from additionalFields even when fields has monthCode"
+);
+assert.deepEqual(
+ cal.mergeFields({ a: 1, b: 2, month: 7, monthCode: "M08" }, { b: 3, c: 4, month: 5, monthCode: "M06" }),
+ { a: 1, b: 3, c: 4, month: 5, monthCode: "M06" },
+ "both month and monthCode are copied from additionalFields even when fields has both month and monthCode"
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/length.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/length.js
new file mode 100644
index 0000000000..fa2778be25
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/length.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.mergefields
+description: Temporal.Calendar.prototype.mergeFields.length is 2
+info: |
+ Every built-in function object, including constructors, has a "length" property whose value is
+ an integer. Unless otherwise specified, this value is equal to the largest number of named
+ arguments shown in the subclause headings for the function description. Optional parameters
+ (which are indicated with brackets: [ ]) or rest parameters (which are shown using the form
+ «...name») are not included in the default argument count.
+
+ Unless otherwise specified, the "length" property of a built-in function object has the
+ attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+verifyProperty(Temporal.Calendar.prototype.mergeFields, "length", {
+ value: 2,
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/name.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/name.js
new file mode 100644
index 0000000000..23c4ea861c
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/name.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.mergefields
+description: Temporal.Calendar.prototype.mergeFields.name is "mergeFields".
+info: |
+ Every built-in function object, including constructors, that is not identified as an anonymous
+ function has a "name" property whose value is a String. Unless otherwise specified, this value
+ is the name that is given to the function in this specification.
+
+ Unless otherwise specified, the "name" property of a built-in function object, if it exists,
+ has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+verifyProperty(Temporal.Calendar.prototype.mergeFields, "name", {
+ value: "mergeFields",
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/non-string-properties.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/non-string-properties.js
new file mode 100644
index 0000000000..b78f828d4f
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/non-string-properties.js
@@ -0,0 +1,58 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// Copyright (C) 2022 Igalia S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.mergefields
+description: Both string and symbol keys from the arguments are merged
+info: |
+ 1. Let calendar be the this value.
+ 2. Perform ? RequireInternalSlot(calendar, [[InitializedTemporalCalendar]]).
+ 3. Assert: calendar.[[Identifier]] is "iso8601".
+ 4. Set fields to ? ToObject(fields).
+ 5. Set additionalFields to ? ToObject(additionalFields).
+ 6. Return ? DefaultMergeFields(fields, additionalFields).
+features: [Temporal]
+---*/
+
+function assertEntriesEqual(actual, expectedEntries, message) {
+ const names = Object.getOwnPropertyNames(actual);
+ const symbols = Object.getOwnPropertySymbols(actual);
+ const actualKeys = names.concat(symbols);
+ assert.sameValue(
+ actualKeys.length,
+ expectedEntries.length,
+ `${message}: expected object to have ${expectedEntries.length} properties, not ${actualKeys.length}:`
+ );
+ for (var index = 0; index < actualKeys.length; index++) {
+ const actualKey = actualKeys[index];
+ const expectedKey = expectedEntries[index][0];
+ const expectedValue = expectedEntries[index][1];
+ assert.sameValue(actualKey, expectedKey, `${message}: key ${index}:`);
+ assert.sameValue(actual[actualKey], expectedValue, `${message}: value ${index}:`);
+ }
+}
+
+const cal = new Temporal.Calendar("iso8601");
+
+assertEntriesEqual(
+ cal.mergeFields({ 1: 2 }, { 3: 4 }),
+ [["1", 2], ["3", 4]],
+ "number keys are actually string keys and are merged as such"
+);
+assertEntriesEqual(
+ cal.mergeFields({ 1n: 2 }, { 2n: 4 }),
+ [["1", 2], ["2", 4]],
+ "bigint keys are actually string keys and are merged as such"
+);
+
+const foo = Symbol("foo");
+const bar = Symbol("bar");
+assertEntriesEqual(
+ cal.mergeFields({ [foo]: 1 }, { [bar]: 2 }),
+ [[foo, 1], [bar, 2]],
+ "symbol keys are also merged"
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/not-a-constructor.js
new file mode 100644
index 0000000000..c53ddcbf32
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/not-a-constructor.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.mergefields
+description: >
+ Temporal.Calendar.prototype.mergeFields does not implement [[Construct]], is not new-able
+info: |
+ Built-in function objects that are not identified as constructors do not implement the
+ [[Construct]] internal method unless otherwise specified in the description of a particular
+ function.
+includes: [isConstructor.js]
+features: [Reflect.construct, Temporal]
+---*/
+
+assert.throws(TypeError, () => {
+ new Temporal.Calendar.prototype.mergeFields();
+}, "Calling as constructor");
+
+assert.sameValue(isConstructor(Temporal.Calendar.prototype.mergeFields), false,
+ "isConstructor(Temporal.Calendar.prototype.mergeFields)");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/order-of-operations.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/order-of-operations.js
new file mode 100644
index 0000000000..38cd82d5ea
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/order-of-operations.js
@@ -0,0 +1,50 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.mergefields
+description: Properties on objects passed to mergeFields() are accessed in the correct order
+features: [Temporal]
+includes: [compareArray.js, temporalHelpers.js]
+---*/
+
+const expected = [
+ // CopyDataProperties on fields
+ "ownKeys fields",
+ "getOwnPropertyDescriptor fields.year",
+ "get fields.year",
+ "getOwnPropertyDescriptor fields.month",
+ "get fields.month",
+ "getOwnPropertyDescriptor fields.day",
+ "get fields.day",
+ "getOwnPropertyDescriptor fields.extra",
+ "get fields.extra",
+ // CopyDataProperties on additionalFields
+ "ownKeys additionalFields",
+ "getOwnPropertyDescriptor additionalFields[3]",
+ "get additionalFields[3]",
+ "getOwnPropertyDescriptor additionalFields.monthCode",
+ "get additionalFields.monthCode",
+ "getOwnPropertyDescriptor additionalFields[Symbol('extra')]",
+ "get additionalFields[Symbol('extra')]",
+];
+const actual = [];
+
+const fields = TemporalHelpers.propertyBagObserver(actual, {
+ year: 2022,
+ month: 10,
+ day: 17,
+ extra: "extra property",
+}, "fields");
+const additionalFields = TemporalHelpers.propertyBagObserver(actual, {
+ [Symbol("extra")]: "extra symbol property",
+ monthCode: "M10",
+ 3: "extra array index property",
+}, "additionalFields");
+
+const instance = new Temporal.Calendar("iso8601");
+instance.mergeFields(fields, additionalFields);
+assert.compareArray(actual, expected, "order of observable operations");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/prop-desc.js
new file mode 100644
index 0000000000..4c4f0e8d56
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/prop-desc.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.mergefields
+description: The "mergeFields" property of Temporal.Calendar.prototype
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+assert.sameValue(
+ typeof Temporal.Calendar.prototype.mergeFields,
+ "function",
+ "`typeof Calendar.prototype.mergeFields` is `function`"
+);
+
+verifyProperty(Temporal.Calendar.prototype, "mergeFields", {
+ writable: true,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/shell.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/shell.js
new file mode 100644
index 0000000000..346758ebd5
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/mergeFields/shell.js
@@ -0,0 +1,353 @@
+// GENERATED, DO NOT EDIT
+// file: deepEqual.js
+// Copyright 2019 Ron Buckton. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: >
+ Compare two values structurally
+defines: [assert.deepEqual]
+---*/
+
+assert.deepEqual = function(actual, expected, message) {
+ var format = assert.deepEqual.format;
+ assert(
+ assert.deepEqual._compare(actual, expected),
+ `Expected ${format(actual)} to be structurally equal to ${format(expected)}. ${(message || '')}`
+ );
+};
+
+assert.deepEqual.format = function(value, seen) {
+ switch (typeof value) {
+ case 'string':
+ return typeof JSON !== "undefined" ? JSON.stringify(value) : `"${value}"`;
+ case 'number':
+ case 'boolean':
+ case 'symbol':
+ case 'bigint':
+ return value.toString();
+ case 'undefined':
+ return 'undefined';
+ case 'function':
+ return `[Function${value.name ? `: ${value.name}` : ''}]`;
+ case 'object':
+ if (value === null) return 'null';
+ if (value instanceof Date) return `Date "${value.toISOString()}"`;
+ if (value instanceof RegExp) return value.toString();
+ if (!seen) {
+ seen = {
+ counter: 0,
+ map: new Map()
+ };
+ }
+
+ let usage = seen.map.get(value);
+ if (usage) {
+ usage.used = true;
+ return `[Ref: #${usage.id}]`;
+ }
+
+ usage = { id: ++seen.counter, used: false };
+ seen.map.set(value, usage);
+
+ if (typeof Set !== "undefined" && value instanceof Set) {
+ return `Set {${Array.from(value).map(value => assert.deepEqual.format(value, seen)).join(', ')}}${usage.used ? ` as #${usage.id}` : ''}`;
+ }
+ if (typeof Map !== "undefined" && value instanceof Map) {
+ return `Map {${Array.from(value).map(pair => `${assert.deepEqual.format(pair[0], seen)} => ${assert.deepEqual.format(pair[1], seen)}}`).join(', ')}}${usage.used ? ` as #${usage.id}` : ''}`;
+ }
+ if (Array.isArray ? Array.isArray(value) : value instanceof Array) {
+ return `[${value.map(value => assert.deepEqual.format(value, seen)).join(', ')}]${usage.used ? ` as #${usage.id}` : ''}`;
+ }
+ let tag = Symbol.toStringTag in value ? value[Symbol.toStringTag] : 'Object';
+ if (tag === 'Object' && Object.getPrototypeOf(value) === null) {
+ tag = '[Object: null prototype]';
+ }
+ return `${tag ? `${tag} ` : ''}{ ${Object.keys(value).map(key => `${key.toString()}: ${assert.deepEqual.format(value[key], seen)}`).join(', ')} }${usage.used ? ` as #${usage.id}` : ''}`;
+ default:
+ return typeof value;
+ }
+};
+
+assert.deepEqual._compare = (function () {
+ var EQUAL = 1;
+ var NOT_EQUAL = -1;
+ var UNKNOWN = 0;
+
+ function deepEqual(a, b) {
+ return compareEquality(a, b) === EQUAL;
+ }
+
+ function compareEquality(a, b, cache) {
+ return compareIf(a, b, isOptional, compareOptionality)
+ || compareIf(a, b, isPrimitiveEquatable, comparePrimitiveEquality)
+ || compareIf(a, b, isObjectEquatable, compareObjectEquality, cache)
+ || NOT_EQUAL;
+ }
+
+ function compareIf(a, b, test, compare, cache) {
+ return !test(a)
+ ? !test(b) ? UNKNOWN : NOT_EQUAL
+ : !test(b) ? NOT_EQUAL : cacheComparison(a, b, compare, cache);
+ }
+
+ function tryCompareStrictEquality(a, b) {
+ return a === b ? EQUAL : UNKNOWN;
+ }
+
+ function tryCompareTypeOfEquality(a, b) {
+ return typeof a !== typeof b ? NOT_EQUAL : UNKNOWN;
+ }
+
+ function tryCompareToStringTagEquality(a, b) {
+ var aTag = Symbol.toStringTag in a ? a[Symbol.toStringTag] : undefined;
+ var bTag = Symbol.toStringTag in b ? b[Symbol.toStringTag] : undefined;
+ return aTag !== bTag ? NOT_EQUAL : UNKNOWN;
+ }
+
+ function isOptional(value) {
+ return value === undefined
+ || value === null;
+ }
+
+ function compareOptionality(a, b) {
+ return tryCompareStrictEquality(a, b)
+ || NOT_EQUAL;
+ }
+
+ function isPrimitiveEquatable(value) {
+ switch (typeof value) {
+ case 'string':
+ case 'number':
+ case 'bigint':
+ case 'boolean':
+ case 'symbol':
+ return true;
+ default:
+ return isBoxed(value);
+ }
+ }
+
+ function comparePrimitiveEquality(a, b) {
+ if (isBoxed(a)) a = a.valueOf();
+ if (isBoxed(b)) b = b.valueOf();
+ return tryCompareStrictEquality(a, b)
+ || tryCompareTypeOfEquality(a, b)
+ || compareIf(a, b, isNaNEquatable, compareNaNEquality)
+ || NOT_EQUAL;
+ }
+
+ function isNaNEquatable(value) {
+ return typeof value === 'number';
+ }
+
+ function compareNaNEquality(a, b) {
+ return isNaN(a) && isNaN(b) ? EQUAL : NOT_EQUAL;
+ }
+
+ function isObjectEquatable(value) {
+ return typeof value === 'object';
+ }
+
+ function compareObjectEquality(a, b, cache) {
+ if (!cache) cache = new Map();
+ return getCache(cache, a, b)
+ || setCache(cache, a, b, EQUAL) // consider equal for now
+ || cacheComparison(a, b, tryCompareStrictEquality, cache)
+ || cacheComparison(a, b, tryCompareToStringTagEquality, cache)
+ || compareIf(a, b, isValueOfEquatable, compareValueOfEquality)
+ || compareIf(a, b, isToStringEquatable, compareToStringEquality)
+ || compareIf(a, b, isArrayLikeEquatable, compareArrayLikeEquality, cache)
+ || compareIf(a, b, isStructurallyEquatable, compareStructuralEquality, cache)
+ || compareIf(a, b, isIterableEquatable, compareIterableEquality, cache)
+ || cacheComparison(a, b, fail, cache);
+ }
+
+ function isBoxed(value) {
+ return value instanceof String
+ || value instanceof Number
+ || value instanceof Boolean
+ || typeof Symbol === 'function' && value instanceof Symbol
+ || typeof BigInt === 'function' && value instanceof BigInt;
+ }
+
+ function isValueOfEquatable(value) {
+ return value instanceof Date;
+ }
+
+ function compareValueOfEquality(a, b) {
+ return compareIf(a.valueOf(), b.valueOf(), isPrimitiveEquatable, comparePrimitiveEquality)
+ || NOT_EQUAL;
+ }
+
+ function isToStringEquatable(value) {
+ return value instanceof RegExp;
+ }
+
+ function compareToStringEquality(a, b) {
+ return compareIf(a.toString(), b.toString(), isPrimitiveEquatable, comparePrimitiveEquality)
+ || NOT_EQUAL;
+ }
+
+ function isArrayLikeEquatable(value) {
+ return (Array.isArray ? Array.isArray(value) : value instanceof Array)
+ || (typeof Uint8Array === 'function' && value instanceof Uint8Array)
+ || (typeof Uint8ClampedArray === 'function' && value instanceof Uint8ClampedArray)
+ || (typeof Uint16Array === 'function' && value instanceof Uint16Array)
+ || (typeof Uint32Array === 'function' && value instanceof Uint32Array)
+ || (typeof Int8Array === 'function' && value instanceof Int8Array)
+ || (typeof Int16Array === 'function' && value instanceof Int16Array)
+ || (typeof Int32Array === 'function' && value instanceof Int32Array)
+ || (typeof Float32Array === 'function' && value instanceof Float32Array)
+ || (typeof Float64Array === 'function' && value instanceof Float64Array)
+ || (typeof BigUint64Array === 'function' && value instanceof BigUint64Array)
+ || (typeof BigInt64Array === 'function' && value instanceof BigInt64Array);
+ }
+
+ function compareArrayLikeEquality(a, b, cache) {
+ if (a.length !== b.length) return NOT_EQUAL;
+ for (var i = 0; i < a.length; i++) {
+ if (compareEquality(a[i], b[i], cache) === NOT_EQUAL) {
+ return NOT_EQUAL;
+ }
+ }
+ return EQUAL;
+ }
+
+ function isStructurallyEquatable(value) {
+ return !(typeof Promise === 'function' && value instanceof Promise // only comparable by reference
+ || typeof WeakMap === 'function' && value instanceof WeakMap // only comparable by reference
+ || typeof WeakSet === 'function' && value instanceof WeakSet // only comparable by reference
+ || typeof Map === 'function' && value instanceof Map // comparable via @@iterator
+ || typeof Set === 'function' && value instanceof Set); // comparable via @@iterator
+ }
+
+ function compareStructuralEquality(a, b, cache) {
+ var aKeys = [];
+ for (var key in a) aKeys.push(key);
+
+ var bKeys = [];
+ for (var key in b) bKeys.push(key);
+
+ if (aKeys.length !== bKeys.length) {
+ return NOT_EQUAL;
+ }
+
+ aKeys.sort();
+ bKeys.sort();
+
+ for (var i = 0; i < aKeys.length; i++) {
+ var aKey = aKeys[i];
+ var bKey = bKeys[i];
+ if (compareEquality(aKey, bKey, cache) === NOT_EQUAL) {
+ return NOT_EQUAL;
+ }
+ if (compareEquality(a[aKey], b[bKey], cache) === NOT_EQUAL) {
+ return NOT_EQUAL;
+ }
+ }
+
+ return compareIf(a, b, isIterableEquatable, compareIterableEquality, cache)
+ || EQUAL;
+ }
+
+ function isIterableEquatable(value) {
+ return typeof Symbol === 'function'
+ && typeof value[Symbol.iterator] === 'function';
+ }
+
+ function compareIteratorEquality(a, b, cache) {
+ if (typeof Map === 'function' && a instanceof Map && b instanceof Map ||
+ typeof Set === 'function' && a instanceof Set && b instanceof Set) {
+ if (a.size !== b.size) return NOT_EQUAL; // exit early if we detect a difference in size
+ }
+
+ var ar, br;
+ while (true) {
+ ar = a.next();
+ br = b.next();
+ if (ar.done) {
+ if (br.done) return EQUAL;
+ if (b.return) b.return();
+ return NOT_EQUAL;
+ }
+ if (br.done) {
+ if (a.return) a.return();
+ return NOT_EQUAL;
+ }
+ if (compareEquality(ar.value, br.value, cache) === NOT_EQUAL) {
+ if (a.return) a.return();
+ if (b.return) b.return();
+ return NOT_EQUAL;
+ }
+ }
+ }
+
+ function compareIterableEquality(a, b, cache) {
+ return compareIteratorEquality(a[Symbol.iterator](), b[Symbol.iterator](), cache);
+ }
+
+ function cacheComparison(a, b, compare, cache) {
+ var result = compare(a, b, cache);
+ if (cache && (result === EQUAL || result === NOT_EQUAL)) {
+ setCache(cache, a, b, /** @type {EQUAL | NOT_EQUAL} */(result));
+ }
+ return result;
+ }
+
+ function fail() {
+ return NOT_EQUAL;
+ }
+
+ function setCache(cache, left, right, result) {
+ var otherCache;
+
+ otherCache = cache.get(left);
+ if (!otherCache) cache.set(left, otherCache = new Map());
+ otherCache.set(right, result);
+
+ otherCache = cache.get(right);
+ if (!otherCache) cache.set(right, otherCache = new Map());
+ otherCache.set(left, result);
+ }
+
+ function getCache(cache, left, right) {
+ var otherCache;
+ var result;
+
+ otherCache = cache.get(left);
+ result = otherCache && otherCache.get(right);
+ if (result) return result;
+
+ otherCache = cache.get(right);
+ result = otherCache && otherCache.get(left);
+ if (result) return result;
+
+ return UNKNOWN;
+ }
+
+ return deepEqual;
+})();
+
+// file: isConstructor.js
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: |
+ Test if a given function is a constructor function.
+defines: [isConstructor]
+features: [Reflect.construct]
+---*/
+
+function isConstructor(f) {
+ if (typeof f !== "function") {
+ throw new Test262Error("isConstructor invoked with a non-function value");
+ }
+
+ try {
+ Reflect.construct(function(){}, [], f);
+ } catch (e) {
+ return false;
+ }
+ return true;
+}
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-builtin-calendar-no-array-iteration.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-builtin-calendar-no-array-iteration.js
new file mode 100644
index 0000000000..f3ad260dbc
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-builtin-calendar-no-array-iteration.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.month
+description: >
+ Calling the method with a property bag argument with a builtin calendar causes
+ no observable array iteration when getting the calendar fields.
+features: [Temporal]
+---*/
+
+const arrayPrototypeSymbolIteratorOriginal = Array.prototype[Symbol.iterator];
+Array.prototype[Symbol.iterator] = function arrayIterator() {
+ throw new Test262Error("Array should not be iterated");
+}
+
+const instance = new Temporal.Calendar("iso8601");
+const arg = { year: 2000, month: 5, day: 2, calendar: "iso8601" };
+instance.month(arg);
+
+Array.prototype[Symbol.iterator] = arrayPrototypeSymbolIteratorOriginal;
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-calendar-datefromfields-called-with-null-prototype-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-calendar-datefromfields-called-with-null-prototype-fields.js
new file mode 100644
index 0000000000..0c45a60cc0
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-calendar-datefromfields-called-with-null-prototype-fields.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.month
+description: >
+ Calendar.dateFromFields method is called with a null-prototype fields object
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarCheckFieldsPrototypePollution();
+const instance = new Temporal.Calendar("iso8601");
+const arg = { year: 2000, month: 5, day: 2, calendar };
+instance.month(arg);
+assert.sameValue(calendar.dateFromFieldsCallCount, 1, "dateFromFields should be called on the property bag's calendar");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-constructor-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-constructor-in-calendar-fields.js
new file mode 100644
index 0000000000..b42eb7eedb
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-constructor-in-calendar-fields.js
@@ -0,0 +1,17 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.month
+description: If a calendar's fields() method returns a field named 'constructor', PrepareTemporalFields should throw a RangeError.
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarWithExtraFields(['constructor']);
+const arg = {year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar};
+const instance = new Temporal.Calendar("iso8601");
+
+assert.throws(RangeError, () => instance.month(arg));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-duplicate-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-duplicate-calendar-fields.js
new file mode 100644
index 0000000000..6c9458de2b
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-duplicate-calendar-fields.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.month
+description: If a calendar's fields() method returns duplicate field names, PrepareTemporalFields should throw a RangeError.
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+for (const extra_fields of [['foo', 'foo'], ['day'], ['month'], ['monthCode'], ['year']]) {
+ const calendar = TemporalHelpers.calendarWithExtraFields(extra_fields);
+ const arg = { year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar };
+ const instance = new Temporal.Calendar("iso8601");
+
+ assert.throws(RangeError, () => instance.month(arg));
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-leap-second.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-leap-second.js
new file mode 100644
index 0000000000..faaa158e03
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-leap-second.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.month
+description: Leap second is a valid ISO string for PlainDate
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+let arg = "2016-12-31T23:59:60";
+const result1 = instance.month(arg);
+assert.sameValue(
+ result1,
+ 12,
+ "leap second is a valid ISO string for PlainDate"
+);
+
+arg = { year: 2016, month: 12, day: 31, hour: 23, minute: 59, second: 60 };
+const result2 = instance.month(arg);
+assert.sameValue(
+ result2,
+ 12,
+ "second: 60 is ignored in property bag for PlainDate"
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-number.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-number.js
new file mode 100644
index 0000000000..e9ad09de4b
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-number.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.month
+description: A number cannot be used in place of a Temporal.PlainDate
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const numbers = [
+ 1,
+ 19761118,
+ -19761118,
+ 1234567890,
+];
+
+for (const arg of numbers) {
+ assert.throws(
+ TypeError,
+ () => instance.month(arg),
+ 'Numbers cannot be used in place of an ISO string for PlainDate'
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-propertybag-calendar-case-insensitive.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-propertybag-calendar-case-insensitive.js
new file mode 100644
index 0000000000..0bd26a63b8
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-propertybag-calendar-case-insensitive.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.month
+description: The calendar name is case-insensitive
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const calendar = "IsO8601";
+
+const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+const result = instance.month(arg);
+assert.sameValue(result, 11, "Calendar is case-insensitive");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-propertybag-calendar-leap-second.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-propertybag-calendar-leap-second.js
new file mode 100644
index 0000000000..7af34e9cb0
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-propertybag-calendar-leap-second.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.month
+description: Leap second is a valid ISO string for a calendar in a property bag
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const calendar = "2016-12-31T23:59:60";
+
+const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+const result = instance.month(arg);
+assert.sameValue(
+ result,
+ 11,
+ "leap second is a valid ISO string for calendar"
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-propertybag-calendar-number.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-propertybag-calendar-number.js
new file mode 100644
index 0000000000..dd8ce27a1b
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-propertybag-calendar-number.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.month
+description: A number as calendar in a property bag is not accepted
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const numbers = [
+ 1,
+ 19970327,
+ -19970327,
+ 1234567890,
+];
+
+for (const calendar of numbers) {
+ const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+ assert.throws(
+ TypeError,
+ () => instance.month(arg),
+ "Numbers cannot be used as a calendar"
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-propertybag-calendar-string.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-propertybag-calendar-string.js
new file mode 100644
index 0000000000..b7d15b225b
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-propertybag-calendar-string.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.month
+description: A calendar ID is valid input for Calendar
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const calendar = "iso8601";
+
+const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+const result = instance.month(arg);
+assert.sameValue(result, 11, `Calendar created from string "${calendar}"`);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-propertybag-calendar-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-propertybag-calendar-wrong-type.js
new file mode 100644
index 0000000000..173852f0b7
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-propertybag-calendar-wrong-type.js
@@ -0,0 +1,46 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.month
+description: >
+ Appropriate error thrown when a calendar property from a property bag cannot
+ be converted to a calendar object or string
+features: [BigInt, Symbol, Temporal]
+---*/
+
+const timeZone = new Temporal.TimeZone("UTC");
+const instance = new Temporal.Calendar("iso8601");
+
+const primitiveTests = [
+ [null, "null"],
+ [true, "boolean"],
+ ["", "empty string"],
+ [1, "number that doesn't convert to a valid ISO string"],
+ [1n, "bigint"],
+];
+
+for (const [calendar, description] of primitiveTests) {
+ const arg = { year: 2019, monthCode: "M11", day: 1, calendar };
+ assert.throws(
+ typeof calendar === 'string' ? RangeError : TypeError,
+ () => instance.month(arg),
+ `${description} does not convert to a valid ISO string`
+ );
+}
+
+const typeErrorTests = [
+ [Symbol(), "symbol"],
+ [{}, "plain object that doesn't implement the protocol"],
+ [new Temporal.TimeZone("UTC"), "time zone instance"],
+ [Temporal.Calendar, "Temporal.Calendar, object"],
+ [Temporal.Calendar.prototype, "Temporal.Calendar.prototype, object"], // fails brand check in dateFromFields()
+];
+
+for (const [calendar, description] of typeErrorTests) {
+ const arg = { year: 2019, monthCode: "M11", day: 1, calendar };
+ assert.throws(TypeError, () => instance.month(arg), `${description} is not a valid property bag and does not convert to a string`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-propertybag-calendar-year-zero.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-propertybag-calendar-year-zero.js
new file mode 100644
index 0000000000..81bd484995
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-propertybag-calendar-year-zero.js
@@ -0,0 +1,27 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.month
+description: Negative zero, as an extended year, is rejected
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ "-000000-10-31",
+ "-000000-10-31T17:45",
+ "-000000-10-31T17:45Z",
+ "-000000-10-31T17:45+01:00",
+ "-000000-10-31T17:45+00:00[UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.month(arg),
+ "reject minus zero as extended year"
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-proto-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-proto-in-calendar-fields.js
new file mode 100644
index 0000000000..f81d9391a4
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-proto-in-calendar-fields.js
@@ -0,0 +1,17 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.month
+description: If a calendar's fields() method returns a field named '__proto__', PrepareTemporalFields should throw a RangeError.
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarWithExtraFields(['__proto__']);
+const arg = {year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar};
+const instance = new Temporal.Calendar("iso8601");
+
+assert.throws(RangeError, () => instance.month(arg));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-string-calendar-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-string-calendar-annotation.js
new file mode 100644
index 0000000000..ac8502eab0
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-string-calendar-annotation.js
@@ -0,0 +1,33 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.month
+description: Various forms of calendar annotation; critical flag has no effect
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02[u-ca=iso8601]", "without time or time zone"],
+ ["2000-05-02[UTC][u-ca=iso8601]", "with time zone and no time"],
+ ["2000-05-02T15:23[u-ca=iso8601]", "without time zone"],
+ ["2000-05-02T15:23[UTC][u-ca=iso8601]", "with time zone"],
+ ["2000-05-02T15:23[!u-ca=iso8601]", "with ! and no time zone"],
+ ["2000-05-02T15:23[UTC][!u-ca=iso8601]", "with ! and time zone"],
+ ["2000-05-02T15:23[u-ca=iso8601][u-ca=discord]", "second annotation ignored"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.month(arg);
+
+ assert.sameValue(
+ result,
+ 5,
+ `calendar annotation (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-string-critical-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-string-critical-unknown-annotation.js
new file mode 100644
index 0000000000..fbd525323b
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-string-critical-unknown-annotation.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.month
+description: Unknown annotations with critical flag are rejected
+features: [Temporal]
+---*/
+
+const invalidStrings = [
+ "1970-01-01[!foo=bar]",
+ "1970-01-01T00:00[!foo=bar]",
+ "1970-01-01T00:00[UTC][!foo=bar]",
+ "1970-01-01T00:00[u-ca=iso8601][!foo=bar]",
+ "1970-01-01T00:00[UTC][!foo=bar][u-ca=iso8601]",
+ "1970-01-01T00:00[foo=bar][!_foo-bar0=Dont-Ignore-This-99999999999]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.month(arg),
+ `reject unknown annotation with critical flag: ${arg}`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-string-date-with-utc-offset.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-string-date-with-utc-offset.js
new file mode 100644
index 0000000000..460fbfdc95
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-string-date-with-utc-offset.js
@@ -0,0 +1,48 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.month
+description: UTC offset not valid with format that does not include a time
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const validStrings = [
+ "2000-05-02T00+00:00",
+ "2000-05-02T00+00:00[UTC]",
+ "2000-05-02T00+00:00[!UTC]",
+ "2000-05-02T00-02:30[America/St_Johns]",
+];
+
+for (const arg of validStrings) {
+ const result = instance.month(arg);
+
+ assert.sameValue(
+ result,
+ 5,
+ `"${arg}" is a valid UTC offset with time for PlainDate`
+ );
+}
+
+const invalidStrings = [
+ "2022-09-15Z",
+ "2022-09-15Z[UTC]",
+ "2022-09-15Z[Europe/Vienna]",
+ "2022-09-15+00:00",
+ "2022-09-15+00:00[UTC]",
+ "2022-09-15-02:30",
+ "2022-09-15-02:30[America/St_Johns]",
+];
+
+for (const arg of invalidStrings) {
+ assert.throws(
+ RangeError,
+ () => instance.month(arg),
+ `"${arg}" UTC offset without time is not valid for PlainDate`
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-string-invalid.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-string-invalid.js
new file mode 100644
index 0000000000..8ef222a838
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-string-invalid.js
@@ -0,0 +1,64 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.month
+description: >
+ RangeError thrown if an invalid ISO string (or syntactically valid ISO string
+ that is not supported) is used as a PlainDate
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ // invalid ISO strings:
+ "",
+ "invalid iso8601",
+ "2020-01-00",
+ "2020-01-32",
+ "2020-02-30",
+ "2021-02-29",
+ "2020-00-01",
+ "2020-13-01",
+ "2020-01-01T",
+ "2020-01-01T25:00:00",
+ "2020-01-01T01:60:00",
+ "2020-01-01T01:60:61",
+ "2020-01-01junk",
+ "2020-01-01T00:00:00junk",
+ "2020-01-01T00:00:00+00:00junk",
+ "2020-01-01T00:00:00+00:00[UTC]junk",
+ "2020-01-01T00:00:00+00:00[UTC][u-ca=iso8601]junk",
+ "02020-01-01",
+ "2020-001-01",
+ "2020-01-001",
+ "2020-01-01T001",
+ "2020-01-01T01:001",
+ "2020-01-01T01:01:001",
+ // valid, but forms not supported in Temporal:
+ "2020-W01-1",
+ "2020-001",
+ "+0002020-01-01",
+ // valid, but this calendar must not exist:
+ "2020-01-01[u-ca=notexist]",
+ // may be valid in other contexts, but insufficient information for PlainDate:
+ "2020-01",
+ "+002020-01",
+ "01-01",
+ "2020-W01",
+ "P1Y",
+ "-P12Y",
+ // valid, but outside the supported range:
+ "-999999-01-01",
+ "+999999-01-01",
+];
+const instance = new Temporal.Calendar("iso8601");
+for (const arg of invalidStrings) {
+ assert.throws(
+ RangeError,
+ () => instance.month(arg),
+ `"${arg}" should not be a valid ISO string for a PlainDate`
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-string-multiple-calendar.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-string-multiple-calendar.js
new file mode 100644
index 0000000000..2318d545b5
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-string-multiple-calendar.js
@@ -0,0 +1,32 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.month
+description: >
+ More than one calendar annotation is not syntactical if any have the criical
+ flag
+features: [Temporal]
+---*/
+
+const invalidStrings = [
+ "1970-01-01[u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01[!u-ca=iso8601][u-ca=iso8601]",
+ "1970-01-01[UTC][u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01[u-ca=iso8601][foo=bar][!u-ca=iso8601]",
+ "1970-01-01T00:00[u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01T00:00[!u-ca=iso8601][u-ca=iso8601]",
+ "1970-01-01T00:00[UTC][u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01T00:00[u-ca=iso8601][foo=bar][!u-ca=iso8601]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.month(arg),
+ `reject more than one calendar annotation if any critical: ${arg}`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-string-multiple-time-zone.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-string-multiple-time-zone.js
new file mode 100644
index 0000000000..abfed3580c
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-string-multiple-time-zone.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.month
+description: More than one time zone annotation is not syntactical
+features: [Temporal]
+---*/
+
+const invalidStrings = [
+ "1970-01-01[UTC][UTC]",
+ "1970-01-01T00:00[UTC][UTC]",
+ "1970-01-01T00:00[!UTC][UTC]",
+ "1970-01-01T00:00[UTC][!UTC]",
+ "1970-01-01T00:00[UTC][u-ca=iso8601][UTC]",
+ "1970-01-01T00:00[UTC][foo=bar][UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.month(arg),
+ `reject more than one time zone annotation: ${arg}`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-string-time-separators.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-string-time-separators.js
new file mode 100644
index 0000000000..6166133d3d
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-string-time-separators.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.month
+description: Time separator in string argument can vary
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02T15:23", "uppercase T"],
+ ["2000-05-02t15:23", "lowercase T"],
+ ["2000-05-02 15:23", "space between date and time"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.month(arg);
+
+ assert.sameValue(
+ result,
+ 5,
+ `variant time separators (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-string-time-zone-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-string-time-zone-annotation.js
new file mode 100644
index 0000000000..d5d9b46388
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-string-time-zone-annotation.js
@@ -0,0 +1,38 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.month
+description: Various forms of time zone annotation; critical flag has no effect
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02[Asia/Kolkata]", "named, with no time"],
+ ["2000-05-02[!Europe/Vienna]", "named, with ! and no time"],
+ ["2000-05-02[+00:00]", "numeric, with no time"],
+ ["2000-05-02[!-02:30]", "numeric, with ! and no time"],
+ ["2000-05-02T15:23[America/Sao_Paulo]", "named, with no offset"],
+ ["2000-05-02T15:23[!Asia/Tokyo]", "named, with ! and no offset"],
+ ["2000-05-02T15:23[-02:30]", "numeric, with no offset"],
+ ["2000-05-02T15:23[!+00:00]", "numeric, with ! and no offset"],
+ ["2000-05-02T15:23+00:00[America/New_York]", "named, with offset"],
+ ["2000-05-02T15:23+00:00[!UTC]", "named, with offset and !"],
+ ["2000-05-02T15:23+00:00[+01:00]", "numeric, with offset"],
+ ["2000-05-02T15:23+00:00[!-08:00]", "numeric, with offset and !"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.month(arg);
+
+ assert.sameValue(
+ result,
+ 5,
+ `time zone annotation (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-string-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-string-unknown-annotation.js
new file mode 100644
index 0000000000..b0eb8ca2e2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-string-unknown-annotation.js
@@ -0,0 +1,32 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.month
+description: Various forms of unknown annotation
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02[foo=bar]", "without time"],
+ ["2000-05-02T15:23[foo=bar]", "alone"],
+ ["2000-05-02T15:23[UTC][foo=bar]", "with time zone"],
+ ["2000-05-02T15:23[u-ca=iso8601][foo=bar]", "with calendar"],
+ ["2000-05-02T15:23[UTC][foo=bar][u-ca=iso8601]", "with time zone and calendar"],
+ ["2000-05-02T15:23[foo=bar][_foo-bar0=Ignore-This-999999999999]", "with another unknown annotation"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.month(arg);
+
+ assert.sameValue(
+ result,
+ 5,
+ `unknown annotation (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-string-with-utc-designator.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-string-with-utc-designator.js
new file mode 100644
index 0000000000..6a85186669
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-string-with-utc-designator.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.month
+description: RangeError thrown if a string with UTC designator is used as a PlainDate
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ "2019-10-01T09:00:00Z",
+ "2019-10-01T09:00:00Z[UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.month(arg),
+ "String with UTC designator should not be valid as a PlainDate"
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-wrong-type.js
new file mode 100644
index 0000000000..2edf45bb54
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-wrong-type.js
@@ -0,0 +1,43 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.month
+description: >
+ Appropriate error thrown when argument cannot be converted to a valid string
+ or property bag for PlainDate
+features: [BigInt, Symbol, Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const primitiveTests = [
+ [undefined, "undefined"],
+ [null, "null"],
+ [true, "boolean"],
+ ["", "empty string"],
+ [1, "number that doesn't convert to a valid ISO string"],
+ [1n, "bigint"],
+];
+
+for (const [arg, description] of primitiveTests) {
+ assert.throws(
+ typeof arg === 'string' ? RangeError : TypeError,
+ () => instance.month(arg),
+ `${description} does not convert to a valid ISO string`
+ );
+}
+
+const typeErrorTests = [
+ [Symbol(), "symbol"],
+ [{}, "plain object"],
+ [Temporal.PlainDate, "Temporal.PlainDate, object"],
+ [Temporal.PlainDate.prototype, "Temporal.PlainDate.prototype, object"],
+];
+
+for (const [arg, description] of typeErrorTests) {
+ assert.throws(TypeError, () => instance.month(arg), `${description} is not a valid property bag and does not convert to a string`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-zoneddatetime-convert.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-zoneddatetime-convert.js
new file mode 100644
index 0000000000..efa7901fbd
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-zoneddatetime-convert.js
@@ -0,0 +1,22 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.month
+description: An exception from TimeZone#getOffsetNanosecondsFor() is propagated.
+features: [Temporal]
+---*/
+
+class TZ extends Temporal.TimeZone {
+ constructor() { super("UTC") }
+ getOffsetNanosecondsFor() { throw new Test262Error() }
+}
+
+const tz = new TZ();
+const arg = new Temporal.ZonedDateTime(0n, tz);
+const instance = new Temporal.Calendar("iso8601");
+
+assert.throws(Test262Error, () => instance.month(arg));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-zoneddatetime-slots.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-zoneddatetime-slots.js
new file mode 100644
index 0000000000..083973936e
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-zoneddatetime-slots.js
@@ -0,0 +1,40 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.month
+description: Getters are not called when converting a ZonedDateTime to a PlainDate.
+includes: [compareArray.js]
+features: [Temporal]
+---*/
+
+const actual = [];
+const prototypeDescrs = Object.getOwnPropertyDescriptors(Temporal.ZonedDateTime.prototype);
+const getters = ["year", "month", "monthCode", "day", "hour", "minute", "second", "millisecond", "microsecond", "nanosecond", "calendar"];
+
+for (const property of getters) {
+ Object.defineProperty(Temporal.ZonedDateTime.prototype, property, {
+ get() {
+ actual.push(`get ${property}`);
+ const value = prototypeDescrs[property].get.call(this);
+ return {
+ toString() {
+ actual.push(`toString ${property}`);
+ return value.toString();
+ },
+ valueOf() {
+ actual.push(`valueOf ${property}`);
+ return value;
+ },
+ };
+ },
+ });
+}
+
+const arg = new Temporal.ZonedDateTime(0n, "UTC");
+const instance = new Temporal.Calendar("iso8601");
+instance.month(arg);
+assert.compareArray(actual, []);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js
new file mode 100644
index 0000000000..a17f4788fa
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.month
+description: RangeError thrown if time zone reports an offset that is not an integer number of nanoseconds
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+[3600_000_000_000.5, NaN, -Infinity, Infinity].forEach((wrongOffset) => {
+ const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset);
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ assert.throws(RangeError, () => calendar.month(datetime));
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js
new file mode 100644
index 0000000000..ee000ce22d
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.month
+description: TypeError thrown if timeZone.getOffsetNanosecondsFor is not callable
+features: [BigInt, Symbol, Temporal, arrow-function]
+---*/
+
+[undefined, null, true, Math.PI, 'string', Symbol('sym'), 42n, {}].forEach((notCallable) => {
+ const timeZone = new Temporal.TimeZone("UTC");
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ timeZone.getOffsetNanosecondsFor = notCallable;
+ assert.throws(
+ TypeError,
+ () => calendar.month(datetime),
+ `Uncallable ${notCallable === null ? 'null' : typeof notCallable} getOffsetNanosecondsFor should throw TypeError`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js
new file mode 100644
index 0000000000..a8c8823177
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.month
+description: RangeError thrown if time zone reports an offset that is out of range
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+[-86400_000_000_000, 86400_000_000_000].forEach((wrongOffset) => {
+ const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset);
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ assert.throws(RangeError, () => calendar.month(datetime));
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js
new file mode 100644
index 0000000000..7ed7627662
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.month
+description: TypeError thrown if time zone reports an offset that is not a Number
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+[
+ undefined,
+ null,
+ true,
+ "+01:00",
+ Symbol(),
+ 3600_000_000_000n,
+ {},
+ { valueOf() { return 3600_000_000_000; } },
+].forEach((wrongOffset) => {
+ const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset);
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ assert.throws(TypeError, () => calendar.month(datetime));
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/basic.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/basic.js
new file mode 100644
index 0000000000..737bcc99bb
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/basic.js
@@ -0,0 +1,21 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.month
+description: Basic tests for month().
+features: [Temporal]
+---*/
+
+const iso = Temporal.Calendar.from("iso8601");
+const res = 11;
+assert.sameValue(iso.month(Temporal.PlainDate.from("1994-11-05")), res, "PlainDate");
+assert.sameValue(iso.month(Temporal.PlainDateTime.from("1994-11-05T08:15:30")), res, "PlainDateTime");
+assert.sameValue(iso.month(Temporal.PlainYearMonth.from("1994-11")), res, "PlainYearMonth");
+assert.sameValue(iso.month({ year: 1994, month: 11, day: 5 }), res, "property bag");
+assert.sameValue(iso.month("1994-11-05"), res, "string");
+assert.throws(TypeError, () => iso.month({ year: 2000 }), "property bag with missing properties");
+assert.throws(TypeError, () => iso.month(Temporal.PlainMonthDay.from("11-05")), "PlainMonthDay");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/branding.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/branding.js
new file mode 100644
index 0000000000..505485af9f
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/branding.js
@@ -0,0 +1,27 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.month
+description: Throw a TypeError if the receiver is invalid
+features: [Symbol, Temporal]
+---*/
+
+const month = Temporal.Calendar.prototype.month;
+
+assert.sameValue(typeof month, "function");
+
+const args = [new Temporal.PlainDate(2000, 1, 1)];
+
+assert.throws(TypeError, () => month.apply(undefined, args), "undefined");
+assert.throws(TypeError, () => month.apply(null, args), "null");
+assert.throws(TypeError, () => month.apply(true, args), "true");
+assert.throws(TypeError, () => month.apply("", args), "empty string");
+assert.throws(TypeError, () => month.apply(Symbol(), args), "symbol");
+assert.throws(TypeError, () => month.apply(1, args), "1");
+assert.throws(TypeError, () => month.apply({}, args), "plain object");
+assert.throws(TypeError, () => month.apply(Temporal.Calendar, args), "Temporal.Calendar");
+assert.throws(TypeError, () => month.apply(Temporal.Calendar.prototype, args), "Temporal.Calendar.prototype");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/browser.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/browser.js
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/builtin.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/builtin.js
new file mode 100644
index 0000000000..398501e3ad
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/builtin.js
@@ -0,0 +1,36 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.month
+description: >
+ Tests that Temporal.Calendar.prototype.month
+ meets the requirements for built-in objects defined by the
+ introduction of chapter 17 of the ECMAScript Language Specification.
+info: |
+ Built-in functions that are not constructors do not have a "prototype" property unless
+ otherwise specified in the description of a particular function.
+
+ Unless specified otherwise, a built-in object that is callable as a function is a built-in
+ function object with the characteristics described in 10.3. Unless specified otherwise, the
+ [[Extensible]] internal slot of a built-in object initially has the value true.
+
+ Unless otherwise specified every built-in function and every built-in constructor has the
+ Function prototype object [...] as the value of its [[Prototype]] internal slot.
+features: [Temporal]
+---*/
+
+assert.sameValue(Object.isExtensible(Temporal.Calendar.prototype.month),
+ true, "Built-in objects must be extensible.");
+
+assert.sameValue(Object.prototype.toString.call(Temporal.Calendar.prototype.month),
+ "[object Function]", "Object.prototype.toString");
+
+assert.sameValue(Object.getPrototypeOf(Temporal.Calendar.prototype.month),
+ Function.prototype, "prototype");
+
+assert.sameValue(Temporal.Calendar.prototype.month.hasOwnProperty("prototype"),
+ false, "prototype property");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/calendar-datefromfields-called-with-options-undefined.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/calendar-datefromfields-called-with-options-undefined.js
new file mode 100644
index 0000000000..b6ad45d5f2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/calendar-datefromfields-called-with-options-undefined.js
@@ -0,0 +1,18 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.month
+description: >
+ Calendar.dateFromFields method is called with undefined as the options value
+ when call originates internally
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions();
+calendar.month({ year: 2000, month: 5, day: 3, calendar });
+assert.sameValue(calendar.dateFromFieldsCallCount, 1);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/calendar-fields-iterable.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/calendar-fields-iterable.js
new file mode 100644
index 0000000000..d43a81b98d
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/calendar-fields-iterable.js
@@ -0,0 +1,37 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.month
+description: Verify the result of calendar.fields() is treated correctly.
+info: |
+ sec-temporal.calendar.prototype.month step 4:
+ 4. Return ? ISOMonth(_dateOrDateTime_).
+ sec-temporal-isomonth step 1.a:
+ a. Set _dateOrDateTime_ to ? ToTemporalDate(_dateOrDateTime_).
+ sec-temporal-totemporaldate step 2.c:
+ c. Let _fieldNames_ be ? CalendarFields(_calendar_, « *"day"*, *"month"*, *"monthCode"*, *"year"* »).
+ sec-temporal-calendarfields step 4:
+ 4. Let _result_ be ? IterableToListOfType(_fieldsArray_, « String »).
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const expected = [
+ "day",
+ "month",
+ "monthCode",
+ "year",
+];
+
+const calendar1 = TemporalHelpers.calendarFieldsIterable();
+const calendar2 = TemporalHelpers.calendarFieldsIterable();
+calendar1.month({ year: 2000, month: 5, day: 2, calendar: calendar2 });
+
+assert.sameValue(calendar1.fieldsCallCount, 0, "fields() method not called");
+assert.sameValue(calendar2.fieldsCallCount, 1, "fields() method called once");
+assert.compareArray(calendar2.fieldsCalledWith[0], expected, "fields() method called with correct args");
+assert(calendar2.iteratorExhausted[0], "iterated through the whole iterable");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/calendar-temporal-object.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/calendar-temporal-object.js
new file mode 100644
index 0000000000..47f9b6875e
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/calendar-temporal-object.js
@@ -0,0 +1,31 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.month
+description: Fast path for converting other Temporal objects to Temporal.Calendar by reading internal slots
+info: |
+ sec-temporal.calendar.prototype.month step 4:
+ 4. Return ? ISOMonth(_dateOrDateTime_).
+ sec-temporal-isomonth step 1.a:
+ a. Set _dateOrDateTime_ to ? ToTemporalDate(_dateOrDateTime_).
+ sec-temporal-totemporaldate step 2.c:
+ c. Let _calendar_ be ? GetTemporalCalendarWithISODefault(_item_).
+ sec-temporal-gettemporalcalendarwithisodefault step 2:
+ 2. Return ? ToTemporalCalendarWithISODefault(_calendar_).
+ sec-temporal-totemporalcalendarwithisodefault step 2:
+ 3. Return ? ToTemporalCalendar(_temporalCalendarLike_).
+ sec-temporal-totemporalcalendar step 1.a:
+ a. If _temporalCalendarLike_ has an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]], [[InitializedTemporalMonthDay]], [[InitializedTemporalYearMonth]], or [[InitializedTemporalZonedDateTime]] internal slot, then
+ i. Return _temporalCalendarLike_.[[Calendar]].
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+TemporalHelpers.checkToTemporalCalendarFastPath((temporalObject) => {
+ const calendar = new Temporal.Calendar("iso8601");
+ calendar.month({ year: 2000, month: 5, day: 2, calendar: temporalObject });
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/date-time.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/date-time.js
new file mode 100644
index 0000000000..a78719d1fc
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/date-time.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.month
+description: >
+ Temporal.Calendar.prototype.month will take PlainDateTime and return
+ the value of the month.
+info: |
+ 5. If Type(temporalDateLike) is not Object or temporalDateLike does not have
+ an [[InitializedTemporalDate]] or [[InitializedTemporalYearMonth]]
+ internal slot, then
+ a. Set temporalDateLike to ? ToTemporalDate(temporalDateLike).
+ 6. Return ! ISOMonth(temporalDateLike).
+features: [Temporal]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+let dateTime = new Temporal.PlainDateTime(1997, 8, 23, 5, 30, 13)
+assert.sameValue(cal.month(dateTime), 8, 'cal.month(new Temporal.PlainDateTime(1997, 8, 23, 5, 30, 13)) must return 8');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/date.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/date.js
new file mode 100644
index 0000000000..c5a2aa42f4
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/date.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.month
+description: >
+ Temporal.Calendar.prototype.month will take PlainDate and return
+ the value of the month.
+info: |
+ 1. Let calendar be the this value.
+ 2. Perform ? RequireInternalSlot(calendar, [[InitializedTemporalCalendar]]).
+ 3. Assert: calendar.[[Identifier]] is "iso8601".
+ 4. If Type(temporalDateLike) is Object and temporalDateLike has an
+ [[InitializedTemporalMonthDay]] internal slot, then
+ a. Throw a TypeError exception.
+ 5. If Type(temporalDateLike) is not Object or temporalDateLike does not have
+ an [[InitializedTemporalDate]] or [[InitializedTemporalYearMonth]]
+ internal slot, then
+ a. Set temporalDateLike to ? ToTemporalDate(temporalDateLike).
+ 6. Return ! ISOMonth(temporalDateLike).
+features: [Temporal]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+let date = new Temporal.PlainDate(2021, 7, 15);
+assert.sameValue(cal.month(date), 7, 'cal.month(new Temporal.PlainDate(2021, 7, 15)) must return 7');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/infinity-throws-rangeerror.js
new file mode 100644
index 0000000000..c54d8d66c5
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/infinity-throws-rangeerror.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: Throws if any value in the property bag is Infinity or -Infinity
+esid: sec-temporal.calendar.prototype.month
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+const base = { year: 2000, month: 5, day: 2 };
+
+[Infinity, -Infinity].forEach((inf) => {
+ ["year", "month", "day"].forEach((prop) => {
+ assert.throws(RangeError, () => instance.month({ ...base, [prop]: inf }), `${prop} property cannot be ${inf}`);
+
+ const calls = [];
+ const obj = TemporalHelpers.toPrimitiveObserver(calls, inf, prop);
+ assert.throws(RangeError, () => instance.month({ ...base, [prop]: obj }));
+ assert.compareArray(calls, [`get ${prop}.valueOf`, `call ${prop}.valueOf`], "it fails after fetching the primitive value");
+ });
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/length.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/length.js
new file mode 100644
index 0000000000..29b41d9b57
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/length.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2020 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.month
+description: Temporal.Calendar.prototype.month.length is 1
+info: |
+ Every built-in function object, including constructors, has a "length" property whose value is
+ an integer. Unless otherwise specified, this value is equal to the largest number of named
+ arguments shown in the subclause headings for the function description. Optional parameters
+ (which are indicated with brackets: [ ]) or rest parameters (which are shown using the form
+ «...name») are not included in the default argument count.
+
+ Unless otherwise specified, the "length" property of a built-in function object has the
+ attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+verifyProperty(Temporal.Calendar.prototype.month, "length", {
+ value: 1,
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/month-day-throw-type-error.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/month-day-throw-type-error.js
new file mode 100644
index 0000000000..2d03d4aa6d
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/month-day-throw-type-error.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.month
+description: >
+ Temporal.Calendar.prototype.month throws TypeError if temporalDateLike
+ is a PlainMonthDay object.
+ ToTemporalDate when temporalDateLike is invalid string.
+info: |
+ 4. If Type(temporalDateLike) is Object and temporalDateLike has an
+ [[InitializedTemporalMonthDay]] internal slot, then
+ a. Throw a TypeError exception.
+features: [Temporal, arrow-function]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+let monthDay = new Temporal.PlainMonthDay(12, 25);
+assert.throws(TypeError, () => cal.month(monthDay),
+ 'cal.month(monthDay) throws a TypeError exception');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/name.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/name.js
new file mode 100644
index 0000000000..1a154f7878
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/name.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.month
+description: Temporal.Calendar.prototype.month.name is "month".
+info: |
+ Every built-in function object, including constructors, that is not identified as an anonymous
+ function has a "name" property whose value is a String. Unless otherwise specified, this value
+ is the name that is given to the function in this specification.
+
+ Unless otherwise specified, the "name" property of a built-in function object, if it exists,
+ has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+verifyProperty(Temporal.Calendar.prototype.month, "name", {
+ value: "month",
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/not-a-constructor.js
new file mode 100644
index 0000000000..daab6ff41d
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/not-a-constructor.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.month
+description: >
+ Temporal.Calendar.prototype.month does not implement [[Construct]], is not new-able
+info: |
+ Built-in function objects that are not identified as constructors do not implement the
+ [[Construct]] internal method unless otherwise specified in the description of a particular
+ function.
+includes: [isConstructor.js]
+features: [Reflect.construct, Temporal]
+---*/
+
+assert.throws(TypeError, () => {
+ new Temporal.Calendar.prototype.month();
+}, "Calling as constructor");
+
+assert.sameValue(isConstructor(Temporal.Calendar.prototype.month), false,
+ "isConstructor(Temporal.Calendar.prototype.month)");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/prop-desc.js
new file mode 100644
index 0000000000..3359b2fdaf
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/prop-desc.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.month
+description: The "month" property of Temporal.Calendar.prototype
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+assert.sameValue(
+ typeof Temporal.Calendar.prototype.month,
+ "function",
+ "`typeof Calendar.prototype.month` is `function`"
+);
+
+verifyProperty(Temporal.Calendar.prototype, "month", {
+ writable: true,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/shell.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/shell.js
new file mode 100644
index 0000000000..eda1477282
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/shell.js
@@ -0,0 +1,24 @@
+// GENERATED, DO NOT EDIT
+// file: isConstructor.js
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: |
+ Test if a given function is a constructor function.
+defines: [isConstructor]
+features: [Reflect.construct]
+---*/
+
+function isConstructor(f) {
+ if (typeof f !== "function") {
+ throw new Test262Error("isConstructor invoked with a non-function value");
+ }
+
+ try {
+ Reflect.construct(function(){}, [], f);
+ } catch (e) {
+ return false;
+ }
+ return true;
+}
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/string.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/string.js
new file mode 100644
index 0000000000..8b6e2f20c4
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/string.js
@@ -0,0 +1,22 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.month
+description: >
+ Temporal.Calendar.prototype.month will take ISO8601 string and return
+ the value of the month.
+info: |
+ 5. If Type(temporalDateLike) is not Object or temporalDateLike does not have
+ an [[InitializedTemporalDate]] or [[InitializedTemporalYearMonth]] internal
+ slot, then
+ a. Set temporalDateLike to ? ToTemporalDate(temporalDateLike).
+ 6. Return ! ISOMonth(temporalDateLike).
+features: [Temporal]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+assert.sameValue(cal.month("2019-03-15"), 3, 'cal.month("2019-03-15") must return 3');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/throw-range-error-ToTemporalDate.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/throw-range-error-ToTemporalDate.js
new file mode 100644
index 0000000000..9b166de02b
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/throw-range-error-ToTemporalDate.js
@@ -0,0 +1,22 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.month
+description: >
+ Temporal.Calendar.prototype.month throws RangeError on
+ ToTemporalDate when temporalDateLike is invalid string.
+info: |
+ 5. If Type(temporalDateLike) is not Object or temporalDateLike
+ does not have an [[InitializedTemporalDate]] or
+ [[InitializedTemporalYearMonth]] internal slot, then
+ a. Set temporalDateLike to ? ToTemporalDate(temporalDateLike).
+features: [Temporal, arrow-function]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+assert.throws(RangeError, () => cal.month("invalid string"),
+ 'cal.month("invalid string") throws a RangeError exception');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/year-month.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/year-month.js
new file mode 100644
index 0000000000..23c6dbc614
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/year-month.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.month
+description: >
+ Temporal.Calendar.prototype.month will take PlainYearMonth and return
+ the value of the month.
+info: |
+ 6. Return ! ISOMonth(temporalDateLike).
+features: [Temporal]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+let yearMonth = new Temporal.PlainYearMonth(1999, 6);
+assert.sameValue(cal.month(yearMonth), 6, 'cal.month(new Temporal.PlainYearMonth(1999, 6)) must return 6');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/year-zero.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/year-zero.js
new file mode 100644
index 0000000000..8468e9c316
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/month/year-zero.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.month
+description: Negative zero, as an extended year, is rejected
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ "-000000-10-31",
+ "-000000-10-31T00:45",
+ "-000000-10-31T00:45+01:00",
+ "-000000-10-31T00:45+00:00[UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.month(arg),
+ "reject minus zero as extended year"
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-builtin-calendar-no-array-iteration.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-builtin-calendar-no-array-iteration.js
new file mode 100644
index 0000000000..8e5875e685
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-builtin-calendar-no-array-iteration.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthcode
+description: >
+ Calling the method with a property bag argument with a builtin calendar causes
+ no observable array iteration when getting the calendar fields.
+features: [Temporal]
+---*/
+
+const arrayPrototypeSymbolIteratorOriginal = Array.prototype[Symbol.iterator];
+Array.prototype[Symbol.iterator] = function arrayIterator() {
+ throw new Test262Error("Array should not be iterated");
+}
+
+const instance = new Temporal.Calendar("iso8601");
+const arg = { year: 2000, month: 5, day: 2, calendar: "iso8601" };
+instance.monthCode(arg);
+
+Array.prototype[Symbol.iterator] = arrayPrototypeSymbolIteratorOriginal;
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-calendar-datefromfields-called-with-null-prototype-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-calendar-datefromfields-called-with-null-prototype-fields.js
new file mode 100644
index 0000000000..1a62ba4e88
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-calendar-datefromfields-called-with-null-prototype-fields.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthcode
+description: >
+ Calendar.dateFromFields method is called with a null-prototype fields object
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarCheckFieldsPrototypePollution();
+const instance = new Temporal.Calendar("iso8601");
+const arg = { year: 2000, month: 5, day: 2, calendar };
+instance.monthCode(arg);
+assert.sameValue(calendar.dateFromFieldsCallCount, 1, "dateFromFields should be called on the property bag's calendar");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-constructor-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-constructor-in-calendar-fields.js
new file mode 100644
index 0000000000..d79f744214
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-constructor-in-calendar-fields.js
@@ -0,0 +1,17 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.monthcode
+description: If a calendar's fields() method returns a field named 'constructor', PrepareTemporalFields should throw a RangeError.
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarWithExtraFields(['constructor']);
+const arg = {year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar};
+const instance = new Temporal.Calendar("iso8601");
+
+assert.throws(RangeError, () => instance.monthCode(arg));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-duplicate-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-duplicate-calendar-fields.js
new file mode 100644
index 0000000000..a2693c6070
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-duplicate-calendar-fields.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.monthcode
+description: If a calendar's fields() method returns duplicate field names, PrepareTemporalFields should throw a RangeError.
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+for (const extra_fields of [['foo', 'foo'], ['day'], ['month'], ['monthCode'], ['year']]) {
+ const calendar = TemporalHelpers.calendarWithExtraFields(extra_fields);
+ const arg = { year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar };
+ const instance = new Temporal.Calendar("iso8601");
+
+ assert.throws(RangeError, () => instance.monthCode(arg));
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-leap-second.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-leap-second.js
new file mode 100644
index 0000000000..7a6fd3166b
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-leap-second.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthcode
+description: Leap second is a valid ISO string for PlainDate
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+let arg = "2016-12-31T23:59:60";
+const result1 = instance.monthCode(arg);
+assert.sameValue(
+ result1,
+ "M12",
+ "leap second is a valid ISO string for PlainDate"
+);
+
+arg = { year: 2016, month: 12, day: 31, hour: 23, minute: 59, second: 60 };
+const result2 = instance.monthCode(arg);
+assert.sameValue(
+ result2,
+ "M12",
+ "second: 60 is ignored in property bag for PlainDate"
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-number.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-number.js
new file mode 100644
index 0000000000..8d4f0a0bdf
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-number.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthcode
+description: A number cannot be used in place of a Temporal.PlainDate
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const numbers = [
+ 1,
+ 19761118,
+ -19761118,
+ 1234567890,
+];
+
+for (const arg of numbers) {
+ assert.throws(
+ TypeError,
+ () => instance.monthCode(arg),
+ 'Numbers cannot be used in place of an ISO string for PlainDate'
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-propertybag-calendar-case-insensitive.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-propertybag-calendar-case-insensitive.js
new file mode 100644
index 0000000000..678a9771fe
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-propertybag-calendar-case-insensitive.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthcode
+description: The calendar name is case-insensitive
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const calendar = "IsO8601";
+
+const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+const result = instance.monthCode(arg);
+assert.sameValue(result, "M11", "Calendar is case-insensitive");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-propertybag-calendar-leap-second.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-propertybag-calendar-leap-second.js
new file mode 100644
index 0000000000..d15cc3d900
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-propertybag-calendar-leap-second.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthcode
+description: Leap second is a valid ISO string for a calendar in a property bag
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const calendar = "2016-12-31T23:59:60";
+
+const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+const result = instance.monthCode(arg);
+assert.sameValue(
+ result,
+ "M11",
+ "leap second is a valid ISO string for calendar"
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-propertybag-calendar-number.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-propertybag-calendar-number.js
new file mode 100644
index 0000000000..a56e94238d
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-propertybag-calendar-number.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthcode
+description: A number as calendar in a property bag is not accepted
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const numbers = [
+ 1,
+ 19970327,
+ -19970327,
+ 1234567890,
+];
+
+for (const calendar of numbers) {
+ const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+ assert.throws(
+ TypeError,
+ () => instance.monthCode(arg),
+ "Numbers cannot be used as a calendar"
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-propertybag-calendar-string.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-propertybag-calendar-string.js
new file mode 100644
index 0000000000..272b8a6495
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-propertybag-calendar-string.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthcode
+description: A calendar ID is valid input for Calendar
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const calendar = "iso8601";
+
+const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+const result = instance.monthCode(arg);
+assert.sameValue(result, "M11", `Calendar created from string "${calendar}"`);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-propertybag-calendar-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-propertybag-calendar-wrong-type.js
new file mode 100644
index 0000000000..457e61182b
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-propertybag-calendar-wrong-type.js
@@ -0,0 +1,46 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthcode
+description: >
+ Appropriate error thrown when a calendar property from a property bag cannot
+ be converted to a calendar object or string
+features: [BigInt, Symbol, Temporal]
+---*/
+
+const timeZone = new Temporal.TimeZone("UTC");
+const instance = new Temporal.Calendar("iso8601");
+
+const primitiveTests = [
+ [null, "null"],
+ [true, "boolean"],
+ ["", "empty string"],
+ [1, "number that doesn't convert to a valid ISO string"],
+ [1n, "bigint"],
+];
+
+for (const [calendar, description] of primitiveTests) {
+ const arg = { year: 2019, monthCode: "M11", day: 1, calendar };
+ assert.throws(
+ typeof calendar === 'string' ? RangeError : TypeError,
+ () => instance.monthCode(arg),
+ `${description} does not convert to a valid ISO string`
+ );
+}
+
+const typeErrorTests = [
+ [Symbol(), "symbol"],
+ [{}, "plain object that doesn't implement the protocol"],
+ [new Temporal.TimeZone("UTC"), "time zone instance"],
+ [Temporal.Calendar, "Temporal.Calendar, object"],
+ [Temporal.Calendar.prototype, "Temporal.Calendar.prototype, object"], // fails brand check in dateFromFields()
+];
+
+for (const [calendar, description] of typeErrorTests) {
+ const arg = { year: 2019, monthCode: "M11", day: 1, calendar };
+ assert.throws(TypeError, () => instance.monthCode(arg), `${description} is not a valid property bag and does not convert to a string`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-propertybag-calendar-year-zero.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-propertybag-calendar-year-zero.js
new file mode 100644
index 0000000000..24178dfdb9
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-propertybag-calendar-year-zero.js
@@ -0,0 +1,27 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthcode
+description: Negative zero, as an extended year, is rejected
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ "-000000-10-31",
+ "-000000-10-31T17:45",
+ "-000000-10-31T17:45Z",
+ "-000000-10-31T17:45+01:00",
+ "-000000-10-31T17:45+00:00[UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.monthCode(arg),
+ "reject minus zero as extended year"
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-proto-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-proto-in-calendar-fields.js
new file mode 100644
index 0000000000..ce95efc5da
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-proto-in-calendar-fields.js
@@ -0,0 +1,17 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.monthcode
+description: If a calendar's fields() method returns a field named '__proto__', PrepareTemporalFields should throw a RangeError.
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarWithExtraFields(['__proto__']);
+const arg = {year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar};
+const instance = new Temporal.Calendar("iso8601");
+
+assert.throws(RangeError, () => instance.monthCode(arg));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-string-calendar-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-string-calendar-annotation.js
new file mode 100644
index 0000000000..6fdc89f24b
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-string-calendar-annotation.js
@@ -0,0 +1,33 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthcode
+description: Various forms of calendar annotation; critical flag has no effect
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02[u-ca=iso8601]", "without time or time zone"],
+ ["2000-05-02[UTC][u-ca=iso8601]", "with time zone and no time"],
+ ["2000-05-02T15:23[u-ca=iso8601]", "without time zone"],
+ ["2000-05-02T15:23[UTC][u-ca=iso8601]", "with time zone"],
+ ["2000-05-02T15:23[!u-ca=iso8601]", "with ! and no time zone"],
+ ["2000-05-02T15:23[UTC][!u-ca=iso8601]", "with ! and time zone"],
+ ["2000-05-02T15:23[u-ca=iso8601][u-ca=discord]", "second annotation ignored"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.monthCode(arg);
+
+ assert.sameValue(
+ result,
+ "M05",
+ `calendar annotation (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-string-critical-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-string-critical-unknown-annotation.js
new file mode 100644
index 0000000000..eb87fb6809
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-string-critical-unknown-annotation.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthcode
+description: Unknown annotations with critical flag are rejected
+features: [Temporal]
+---*/
+
+const invalidStrings = [
+ "1970-01-01[!foo=bar]",
+ "1970-01-01T00:00[!foo=bar]",
+ "1970-01-01T00:00[UTC][!foo=bar]",
+ "1970-01-01T00:00[u-ca=iso8601][!foo=bar]",
+ "1970-01-01T00:00[UTC][!foo=bar][u-ca=iso8601]",
+ "1970-01-01T00:00[foo=bar][!_foo-bar0=Dont-Ignore-This-99999999999]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.monthCode(arg),
+ `reject unknown annotation with critical flag: ${arg}`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-string-date-with-utc-offset.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-string-date-with-utc-offset.js
new file mode 100644
index 0000000000..1079461479
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-string-date-with-utc-offset.js
@@ -0,0 +1,48 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthcode
+description: UTC offset not valid with format that does not include a time
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const validStrings = [
+ "2000-05-02T00+00:00",
+ "2000-05-02T00+00:00[UTC]",
+ "2000-05-02T00+00:00[!UTC]",
+ "2000-05-02T00-02:30[America/St_Johns]",
+];
+
+for (const arg of validStrings) {
+ const result = instance.monthCode(arg);
+
+ assert.sameValue(
+ result,
+ "M05",
+ `"${arg}" is a valid UTC offset with time for PlainDate`
+ );
+}
+
+const invalidStrings = [
+ "2022-09-15Z",
+ "2022-09-15Z[UTC]",
+ "2022-09-15Z[Europe/Vienna]",
+ "2022-09-15+00:00",
+ "2022-09-15+00:00[UTC]",
+ "2022-09-15-02:30",
+ "2022-09-15-02:30[America/St_Johns]",
+];
+
+for (const arg of invalidStrings) {
+ assert.throws(
+ RangeError,
+ () => instance.monthCode(arg),
+ `"${arg}" UTC offset without time is not valid for PlainDate`
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-string-invalid.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-string-invalid.js
new file mode 100644
index 0000000000..06f1861f25
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-string-invalid.js
@@ -0,0 +1,64 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthcode
+description: >
+ RangeError thrown if an invalid ISO string (or syntactically valid ISO string
+ that is not supported) is used as a PlainDate
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ // invalid ISO strings:
+ "",
+ "invalid iso8601",
+ "2020-01-00",
+ "2020-01-32",
+ "2020-02-30",
+ "2021-02-29",
+ "2020-00-01",
+ "2020-13-01",
+ "2020-01-01T",
+ "2020-01-01T25:00:00",
+ "2020-01-01T01:60:00",
+ "2020-01-01T01:60:61",
+ "2020-01-01junk",
+ "2020-01-01T00:00:00junk",
+ "2020-01-01T00:00:00+00:00junk",
+ "2020-01-01T00:00:00+00:00[UTC]junk",
+ "2020-01-01T00:00:00+00:00[UTC][u-ca=iso8601]junk",
+ "02020-01-01",
+ "2020-001-01",
+ "2020-01-001",
+ "2020-01-01T001",
+ "2020-01-01T01:001",
+ "2020-01-01T01:01:001",
+ // valid, but forms not supported in Temporal:
+ "2020-W01-1",
+ "2020-001",
+ "+0002020-01-01",
+ // valid, but this calendar must not exist:
+ "2020-01-01[u-ca=notexist]",
+ // may be valid in other contexts, but insufficient information for PlainDate:
+ "2020-01",
+ "+002020-01",
+ "01-01",
+ "2020-W01",
+ "P1Y",
+ "-P12Y",
+ // valid, but outside the supported range:
+ "-999999-01-01",
+ "+999999-01-01",
+];
+const instance = new Temporal.Calendar("iso8601");
+for (const arg of invalidStrings) {
+ assert.throws(
+ RangeError,
+ () => instance.monthCode(arg),
+ `"${arg}" should not be a valid ISO string for a PlainDate`
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-string-multiple-calendar.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-string-multiple-calendar.js
new file mode 100644
index 0000000000..57d58733e8
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-string-multiple-calendar.js
@@ -0,0 +1,32 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthcode
+description: >
+ More than one calendar annotation is not syntactical if any have the criical
+ flag
+features: [Temporal]
+---*/
+
+const invalidStrings = [
+ "1970-01-01[u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01[!u-ca=iso8601][u-ca=iso8601]",
+ "1970-01-01[UTC][u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01[u-ca=iso8601][foo=bar][!u-ca=iso8601]",
+ "1970-01-01T00:00[u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01T00:00[!u-ca=iso8601][u-ca=iso8601]",
+ "1970-01-01T00:00[UTC][u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01T00:00[u-ca=iso8601][foo=bar][!u-ca=iso8601]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.monthCode(arg),
+ `reject more than one calendar annotation if any critical: ${arg}`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-string-multiple-time-zone.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-string-multiple-time-zone.js
new file mode 100644
index 0000000000..eee5dca1fe
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-string-multiple-time-zone.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthcode
+description: More than one time zone annotation is not syntactical
+features: [Temporal]
+---*/
+
+const invalidStrings = [
+ "1970-01-01[UTC][UTC]",
+ "1970-01-01T00:00[UTC][UTC]",
+ "1970-01-01T00:00[!UTC][UTC]",
+ "1970-01-01T00:00[UTC][!UTC]",
+ "1970-01-01T00:00[UTC][u-ca=iso8601][UTC]",
+ "1970-01-01T00:00[UTC][foo=bar][UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.monthCode(arg),
+ `reject more than one time zone annotation: ${arg}`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-string-time-separators.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-string-time-separators.js
new file mode 100644
index 0000000000..a51b45457f
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-string-time-separators.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthcode
+description: Time separator in string argument can vary
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02T15:23", "uppercase T"],
+ ["2000-05-02t15:23", "lowercase T"],
+ ["2000-05-02 15:23", "space between date and time"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.monthCode(arg);
+
+ assert.sameValue(
+ result,
+ "M05",
+ `variant time separators (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-string-time-zone-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-string-time-zone-annotation.js
new file mode 100644
index 0000000000..0aebca570e
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-string-time-zone-annotation.js
@@ -0,0 +1,38 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthcode
+description: Various forms of time zone annotation; critical flag has no effect
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02[Asia/Kolkata]", "named, with no time"],
+ ["2000-05-02[!Europe/Vienna]", "named, with ! and no time"],
+ ["2000-05-02[+00:00]", "numeric, with no time"],
+ ["2000-05-02[!-02:30]", "numeric, with ! and no time"],
+ ["2000-05-02T15:23[America/Sao_Paulo]", "named, with no offset"],
+ ["2000-05-02T15:23[!Asia/Tokyo]", "named, with ! and no offset"],
+ ["2000-05-02T15:23[-02:30]", "numeric, with no offset"],
+ ["2000-05-02T15:23[!+00:00]", "numeric, with ! and no offset"],
+ ["2000-05-02T15:23+00:00[America/New_York]", "named, with offset"],
+ ["2000-05-02T15:23+00:00[!UTC]", "named, with offset and !"],
+ ["2000-05-02T15:23+00:00[+01:00]", "numeric, with offset"],
+ ["2000-05-02T15:23+00:00[!-08:00]", "numeric, with offset and !"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.monthCode(arg);
+
+ assert.sameValue(
+ result,
+ "M05",
+ `time zone annotation (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-string-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-string-unknown-annotation.js
new file mode 100644
index 0000000000..c129776c7f
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-string-unknown-annotation.js
@@ -0,0 +1,32 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthcode
+description: Various forms of unknown annotation
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02[foo=bar]", "without time"],
+ ["2000-05-02T15:23[foo=bar]", "alone"],
+ ["2000-05-02T15:23[UTC][foo=bar]", "with time zone"],
+ ["2000-05-02T15:23[u-ca=iso8601][foo=bar]", "with calendar"],
+ ["2000-05-02T15:23[UTC][foo=bar][u-ca=iso8601]", "with time zone and calendar"],
+ ["2000-05-02T15:23[foo=bar][_foo-bar0=Ignore-This-999999999999]", "with another unknown annotation"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.monthCode(arg);
+
+ assert.sameValue(
+ result,
+ "M05",
+ `unknown annotation (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-string-with-utc-designator.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-string-with-utc-designator.js
new file mode 100644
index 0000000000..bbaf4e93a7
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-string-with-utc-designator.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthcode
+description: RangeError thrown if a string with UTC designator is used as a PlainDate
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ "2019-10-01T09:00:00Z",
+ "2019-10-01T09:00:00Z[UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.monthCode(arg),
+ "String with UTC designator should not be valid as a PlainDate"
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-wrong-type.js
new file mode 100644
index 0000000000..c48b97ca0f
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-wrong-type.js
@@ -0,0 +1,43 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthcode
+description: >
+ Appropriate error thrown when argument cannot be converted to a valid string
+ or property bag for PlainDate
+features: [BigInt, Symbol, Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const primitiveTests = [
+ [undefined, "undefined"],
+ [null, "null"],
+ [true, "boolean"],
+ ["", "empty string"],
+ [1, "number that doesn't convert to a valid ISO string"],
+ [1n, "bigint"],
+];
+
+for (const [arg, description] of primitiveTests) {
+ assert.throws(
+ typeof arg === 'string' ? RangeError : TypeError,
+ () => instance.monthCode(arg),
+ `${description} does not convert to a valid ISO string`
+ );
+}
+
+const typeErrorTests = [
+ [Symbol(), "symbol"],
+ [{}, "plain object"],
+ [Temporal.PlainDate, "Temporal.PlainDate, object"],
+ [Temporal.PlainDate.prototype, "Temporal.PlainDate.prototype, object"],
+];
+
+for (const [arg, description] of typeErrorTests) {
+ assert.throws(TypeError, () => instance.monthCode(arg), `${description} is not a valid property bag and does not convert to a string`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-zoneddatetime-convert.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-zoneddatetime-convert.js
new file mode 100644
index 0000000000..310546e282
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-zoneddatetime-convert.js
@@ -0,0 +1,22 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthcode
+description: An exception from TimeZone#getOffsetNanosecondsFor() is propagated.
+features: [Temporal]
+---*/
+
+class TZ extends Temporal.TimeZone {
+ constructor() { super("UTC") }
+ getOffsetNanosecondsFor() { throw new Test262Error() }
+}
+
+const tz = new TZ();
+const arg = new Temporal.ZonedDateTime(0n, tz);
+const instance = new Temporal.Calendar("iso8601");
+
+assert.throws(Test262Error, () => instance.monthCode(arg));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-zoneddatetime-slots.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-zoneddatetime-slots.js
new file mode 100644
index 0000000000..66651d80d8
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-zoneddatetime-slots.js
@@ -0,0 +1,40 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthcode
+description: Getters are not called when converting a ZonedDateTime to a PlainDate.
+includes: [compareArray.js]
+features: [Temporal]
+---*/
+
+const actual = [];
+const prototypeDescrs = Object.getOwnPropertyDescriptors(Temporal.ZonedDateTime.prototype);
+const getters = ["year", "month", "monthCode", "day", "hour", "minute", "second", "millisecond", "microsecond", "nanosecond", "calendar"];
+
+for (const property of getters) {
+ Object.defineProperty(Temporal.ZonedDateTime.prototype, property, {
+ get() {
+ actual.push(`get ${property}`);
+ const value = prototypeDescrs[property].get.call(this);
+ return {
+ toString() {
+ actual.push(`toString ${property}`);
+ return value.toString();
+ },
+ valueOf() {
+ actual.push(`valueOf ${property}`);
+ return value;
+ },
+ };
+ },
+ });
+}
+
+const arg = new Temporal.ZonedDateTime(0n, "UTC");
+const instance = new Temporal.Calendar("iso8601");
+instance.monthCode(arg);
+assert.compareArray(actual, []);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js
new file mode 100644
index 0000000000..75cc814a12
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthcode
+description: RangeError thrown if time zone reports an offset that is not an integer number of nanoseconds
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+[3600_000_000_000.5, NaN, -Infinity, Infinity].forEach((wrongOffset) => {
+ const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset);
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ assert.throws(RangeError, () => calendar.monthCode(datetime));
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js
new file mode 100644
index 0000000000..52d16e579f
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthcode
+description: TypeError thrown if timeZone.getOffsetNanosecondsFor is not callable
+features: [BigInt, Symbol, Temporal, arrow-function]
+---*/
+
+[undefined, null, true, Math.PI, 'string', Symbol('sym'), 42n, {}].forEach((notCallable) => {
+ const timeZone = new Temporal.TimeZone("UTC");
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ timeZone.getOffsetNanosecondsFor = notCallable;
+ assert.throws(
+ TypeError,
+ () => calendar.monthCode(datetime),
+ `Uncallable ${notCallable === null ? 'null' : typeof notCallable} getOffsetNanosecondsFor should throw TypeError`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js
new file mode 100644
index 0000000000..c9a0bdf5a0
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthcode
+description: RangeError thrown if time zone reports an offset that is out of range
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+[-86400_000_000_000, 86400_000_000_000].forEach((wrongOffset) => {
+ const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset);
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ assert.throws(RangeError, () => calendar.monthCode(datetime));
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js
new file mode 100644
index 0000000000..c5f71da604
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthcode
+description: TypeError thrown if time zone reports an offset that is not a Number
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+[
+ undefined,
+ null,
+ true,
+ "+01:00",
+ Symbol(),
+ 3600_000_000_000n,
+ {},
+ { valueOf() { return 3600_000_000_000; } },
+].forEach((wrongOffset) => {
+ const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset);
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ assert.throws(TypeError, () => calendar.monthCode(datetime));
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/basic.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/basic.js
new file mode 100644
index 0000000000..6d841cf1f9
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/basic.js
@@ -0,0 +1,21 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthcode
+description: Basic tests for monthCode().
+features: [Temporal]
+---*/
+
+const iso = Temporal.Calendar.from("iso8601");
+const res = "M11";
+assert.sameValue(iso.monthCode(Temporal.PlainDate.from("1994-11-05")), res, "PlainDate");
+assert.sameValue(iso.monthCode(Temporal.PlainDateTime.from("1994-11-05T08:15:30")), res, "PlainDateTime");
+assert.sameValue(iso.monthCode(Temporal.PlainYearMonth.from("1994-11")), res, "PlainYearMonth");
+assert.sameValue(iso.monthCode(Temporal.PlainMonthDay.from("11-05")), res, "PlainMonthDay");
+assert.sameValue(iso.monthCode({ year: 1994, month: 11, day: 5 }), res, "property bag");
+assert.sameValue(iso.monthCode("1994-11-05"), res, "string");
+assert.throws(TypeError, () => iso.monthCode({ year: 2000 }), "property bag with missing properties");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/branding.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/branding.js
new file mode 100644
index 0000000000..cd47822052
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/branding.js
@@ -0,0 +1,27 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthcode
+description: Throw a TypeError if the receiver is invalid
+features: [Symbol, Temporal]
+---*/
+
+const monthCode = Temporal.Calendar.prototype.monthCode;
+
+assert.sameValue(typeof monthCode, "function");
+
+const args = [new Temporal.PlainDate(2000, 1, 1)];
+
+assert.throws(TypeError, () => monthCode.apply(undefined, args), "undefined");
+assert.throws(TypeError, () => monthCode.apply(null, args), "null");
+assert.throws(TypeError, () => monthCode.apply(true, args), "true");
+assert.throws(TypeError, () => monthCode.apply("", args), "empty string");
+assert.throws(TypeError, () => monthCode.apply(Symbol(), args), "symbol");
+assert.throws(TypeError, () => monthCode.apply(1, args), "1");
+assert.throws(TypeError, () => monthCode.apply({}, args), "plain object");
+assert.throws(TypeError, () => monthCode.apply(Temporal.Calendar, args), "Temporal.Calendar");
+assert.throws(TypeError, () => monthCode.apply(Temporal.Calendar.prototype, args), "Temporal.Calendar.prototype");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/browser.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/browser.js
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/builtin.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/builtin.js
new file mode 100644
index 0000000000..7ec3413f6d
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/builtin.js
@@ -0,0 +1,36 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthcode
+description: >
+ Tests that Temporal.Calendar.prototype.monthCode
+ meets the requirements for built-in objects defined by the
+ introduction of chapter 17 of the ECMAScript Language Specification.
+info: |
+ Built-in functions that are not constructors do not have a "prototype" property unless
+ otherwise specified in the description of a particular function.
+
+ Unless specified otherwise, a built-in object that is callable as a function is a built-in
+ function object with the characteristics described in 10.3. Unless specified otherwise, the
+ [[Extensible]] internal slot of a built-in object initially has the value true.
+
+ Unless otherwise specified every built-in function and every built-in constructor has the
+ Function prototype object [...] as the value of its [[Prototype]] internal slot.
+features: [Temporal]
+---*/
+
+assert.sameValue(Object.isExtensible(Temporal.Calendar.prototype.monthCode),
+ true, "Built-in objects must be extensible.");
+
+assert.sameValue(Object.prototype.toString.call(Temporal.Calendar.prototype.monthCode),
+ "[object Function]", "Object.prototype.toString");
+
+assert.sameValue(Object.getPrototypeOf(Temporal.Calendar.prototype.monthCode),
+ Function.prototype, "prototype");
+
+assert.sameValue(Temporal.Calendar.prototype.monthCode.hasOwnProperty("prototype"),
+ false, "prototype property");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/calendar-datefromfields-called-with-options-undefined.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/calendar-datefromfields-called-with-options-undefined.js
new file mode 100644
index 0000000000..cb047b7afe
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/calendar-datefromfields-called-with-options-undefined.js
@@ -0,0 +1,18 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthcode
+description: >
+ Calendar.dateFromFields method is called with undefined as the options value
+ when call originates internally
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions();
+calendar.monthCode({ year: 2000, month: 5, day: 3, calendar });
+assert.sameValue(calendar.dateFromFieldsCallCount, 1);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/calendar-fields-iterable.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/calendar-fields-iterable.js
new file mode 100644
index 0000000000..848ff29298
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/calendar-fields-iterable.js
@@ -0,0 +1,37 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthcode
+description: Verify the result of calendar.fields() is treated correctly.
+info: |
+ sec-temporal.calendar.prototype.monthcode step 4:
+ 4. Return ? ISOMonthCode(_dateOrDateTime_).
+ sec-temporal-isomonthcode step 1.a:
+ a. Set _dateOrDateTime_ to ? ToTemporalDate(_dateOrDateTime_).
+ sec-temporal-totemporaldate step 2.c:
+ c. Let _fieldNames_ be ? CalendarFields(_calendar_, « *"day"*, *"month"*, *"monthCode"*, *"year"* »).
+ sec-temporal-calendarfields step 4:
+ 4. Let _result_ be ? IterableToListOfType(_fieldsArray_, « String »).
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const expected = [
+ "day",
+ "month",
+ "monthCode",
+ "year",
+];
+
+const calendar1 = TemporalHelpers.calendarFieldsIterable();
+const calendar2 = TemporalHelpers.calendarFieldsIterable();
+calendar1.monthCode({ year: 2000, month: 5, day: 2, calendar: calendar2 });
+
+assert.sameValue(calendar1.fieldsCallCount, 0, "fields() method not called");
+assert.sameValue(calendar2.fieldsCallCount, 1, "fields() method called once");
+assert.compareArray(calendar2.fieldsCalledWith[0], expected, "fields() method called with correct args");
+assert(calendar2.iteratorExhausted[0], "iterated through the whole iterable");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/calendar-temporal-object.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/calendar-temporal-object.js
new file mode 100644
index 0000000000..097aede616
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/calendar-temporal-object.js
@@ -0,0 +1,31 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthcode
+description: Fast path for converting other Temporal objects to Temporal.Calendar by reading internal slots
+info: |
+ sec-temporal.calendar.prototype.monthcode step 4:
+ 4. Return ? ISOMonthCode(_dateOrDateTime_).
+ sec-temporal-isomonthcode step 1.a:
+ a. Set _dateOrDateTime_ to ? ToTemporalDate(_dateOrDateTime_).
+ sec-temporal-totemporaldate step 2.c:
+ c. Let _calendar_ be ? GetTemporalCalendarWithISODefault(_item_).
+ sec-temporal-gettemporalcalendarwithisodefault step 2:
+ 2. Return ? ToTemporalCalendarWithISODefault(_calendar_).
+ sec-temporal-totemporalcalendarwithisodefault step 2:
+ 3. Return ? ToTemporalCalendar(_temporalCalendarLike_).
+ sec-temporal-totemporalcalendar step 1.a:
+ a. If _temporalCalendarLike_ has an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]], [[InitializedTemporalMonthDay]], [[InitializedTemporalYearMonth]], or [[InitializedTemporalZonedDateTime]] internal slot, then
+ i. Return _temporalCalendarLike_.[[Calendar]].
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+TemporalHelpers.checkToTemporalCalendarFastPath((temporalObject) => {
+ const calendar = new Temporal.Calendar("iso8601");
+ calendar.monthCode({ year: 2000, month: 5, day: 2, calendar: temporalObject });
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/date-time.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/date-time.js
new file mode 100644
index 0000000000..067d4187ad
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/date-time.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthCode
+description: >
+ Temporal.Calendar.prototype.month will take PlainDateTime and return
+ the value of the monthCode.
+info: |
+ 6. Return ! ISOMonthCode(temporalDateLike).
+features: [Temporal]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+let dateTime = new Temporal.PlainDateTime(1997, 8, 23, 5, 30, 13)
+assert.sameValue(
+ cal.monthCode(dateTime),
+ "M08",
+ 'cal.monthCode(new Temporal.PlainDateTime(1997, 8, 23, 5, 30, 13)) must return "M08"'
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/date.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/date.js
new file mode 100644
index 0000000000..4493a17377
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/date.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthCode
+description: >
+ Temporal.Calendar.prototype.monthCode will take PlainDate and return
+ the value of the monthCode.
+info: |
+ 5. Return ! ISOMonthCode(temporalDateLike).
+features: [Temporal]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+let date = new Temporal.PlainDate(2021, 7, 15);
+assert.sameValue(cal.monthCode(date), "M07", 'cal.monthCode(new Temporal.PlainDate(2021, 7, 15)) must return "M07"');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/infinity-throws-rangeerror.js
new file mode 100644
index 0000000000..838f979d19
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/infinity-throws-rangeerror.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: Throws if any value in the property bag is Infinity or -Infinity
+esid: sec-temporal.calendar.prototype.monthcode
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+const base = { year: 2000, month: 5, day: 2 };
+
+[Infinity, -Infinity].forEach((inf) => {
+ ["year", "month", "day"].forEach((prop) => {
+ assert.throws(RangeError, () => instance.monthCode({ ...base, [prop]: inf }), `${prop} property cannot be ${inf}`);
+
+ const calls = [];
+ const obj = TemporalHelpers.toPrimitiveObserver(calls, inf, prop);
+ assert.throws(RangeError, () => instance.monthCode({ ...base, [prop]: obj }));
+ assert.compareArray(calls, [`get ${prop}.valueOf`, `call ${prop}.valueOf`], "it fails after fetching the primitive value");
+ });
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/length.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/length.js
new file mode 100644
index 0000000000..7556b38e55
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/length.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthcode
+description: Temporal.Calendar.prototype.monthCode.length is 1
+info: |
+ Every built-in function object, including constructors, has a "length" property whose value is
+ an integer. Unless otherwise specified, this value is equal to the largest number of named
+ arguments shown in the subclause headings for the function description. Optional parameters
+ (which are indicated with brackets: [ ]) or rest parameters (which are shown using the form
+ «...name») are not included in the default argument count.
+
+ Unless otherwise specified, the "length" property of a built-in function object has the
+ attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+verifyProperty(Temporal.Calendar.prototype.monthCode, "length", {
+ value: 1,
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/month-day.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/month-day.js
new file mode 100644
index 0000000000..23b0f65468
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/month-day.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthCode
+description: >
+ Temporal.Calendar.prototype.monthCode will take PlainMonthDay and return
+ the value of the monthCode.
+info: |
+ 6. Return ! ISOMonthCode(temporalDateLike).
+features: [Temporal]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+let monthDay = new Temporal.PlainMonthDay(12, 25);
+assert.sameValue(
+ cal.monthCode(monthDay),
+ "M12",
+ 'cal.monthCode(new Temporal.PlainMonthDay(12, 25)) must return "M12"'
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/name.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/name.js
new file mode 100644
index 0000000000..4550c2cdc3
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/name.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthcode
+description: Temporal.Calendar.prototype.monthCode.name is "monthCode".
+info: |
+ Every built-in function object, including constructors, that is not identified as an anonymous
+ function has a "name" property whose value is a String. Unless otherwise specified, this value
+ is the name that is given to the function in this specification.
+
+ Unless otherwise specified, the "name" property of a built-in function object, if it exists,
+ has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+verifyProperty(Temporal.Calendar.prototype.monthCode, "name", {
+ value: "monthCode",
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/not-a-constructor.js
new file mode 100644
index 0000000000..e79c22ca20
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/not-a-constructor.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthcode
+description: >
+ Temporal.Calendar.prototype.monthCode does not implement [[Construct]], is not new-able
+info: |
+ Built-in function objects that are not identified as constructors do not implement the
+ [[Construct]] internal method unless otherwise specified in the description of a particular
+ function.
+includes: [isConstructor.js]
+features: [Reflect.construct, Temporal]
+---*/
+
+assert.throws(TypeError, () => {
+ new Temporal.Calendar.prototype.monthCode();
+}, "Calling as constructor");
+
+assert.sameValue(isConstructor(Temporal.Calendar.prototype.monthCode), false,
+ "isConstructor(Temporal.Calendar.prototype.monthCode)");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/prop-desc.js
new file mode 100644
index 0000000000..2e22953632
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/prop-desc.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthcode
+description: The "monthCode" property of Temporal.Calendar.prototype
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+assert.sameValue(
+ typeof Temporal.Calendar.prototype.monthCode,
+ "function",
+ "`typeof Calendar.prototype.monthCode` is `function`"
+);
+
+verifyProperty(Temporal.Calendar.prototype, "monthCode", {
+ writable: true,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/shell.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/shell.js
new file mode 100644
index 0000000000..eda1477282
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/shell.js
@@ -0,0 +1,24 @@
+// GENERATED, DO NOT EDIT
+// file: isConstructor.js
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: |
+ Test if a given function is a constructor function.
+defines: [isConstructor]
+features: [Reflect.construct]
+---*/
+
+function isConstructor(f) {
+ if (typeof f !== "function") {
+ throw new Test262Error("isConstructor invoked with a non-function value");
+ }
+
+ try {
+ Reflect.construct(function(){}, [], f);
+ } catch (e) {
+ return false;
+ }
+ return true;
+}
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/string.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/string.js
new file mode 100644
index 0000000000..1bd095b893
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/string.js
@@ -0,0 +1,25 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthCode
+description: >
+ Temporal.Calendar.prototype.monthCode will take ISO8601 string and return
+ the value of the monthCode.
+info: |
+ 5. If Type(temporalDateLike) is not Object or temporalDateLike does not have
+ an [[InitializedTemporalDate]] or [[InitializedTemporalYearMonth]] internal
+ slot, then
+ a. Set temporalDateLike to ? ToTemporalDate(temporalDateLike).
+ 6. Return ! ISOYear(temporalDateLike).
+features: [Temporal]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+assert.sameValue(
+ cal.monthCode("2019-03-15"),
+ "M03",
+ 'cal.monthCode("2019-03-15") must return "M03"'
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/throw-range-error-ToTemporalDate.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/throw-range-error-ToTemporalDate.js
new file mode 100644
index 0000000000..80ea2299f0
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/throw-range-error-ToTemporalDate.js
@@ -0,0 +1,22 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthCode
+description: >
+ Temporal.Calendar.prototype.monthCode throws RangeError on
+ ToTemporalDate when temporalDateLike is invalid string.
+info: |
+ 4. If Type(temporalDateLike) is not Object or temporalDateLike
+ does not have an [[InitializedTemporalDate]] or
+ [[InitializedTemporalYearMonth]] internal slot, then
+ a. Set temporalDateLike to ? ToTemporalDate(temporalDateLike).
+features: [Temporal, arrow-function]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+assert.throws(RangeError, () => cal.monthCode("invalid string"),
+ 'cal.monthCode("invalid string") throws a RangeError exception');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/year-month.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/year-month.js
new file mode 100644
index 0000000000..c0b553658e
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/year-month.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthCode
+description: >
+ Temporal.Calendar.prototype.monthCode will take PlainYearMonth and return
+ the value of the monthCode.
+info: |
+ 6. Return ! ISOMonthCode(temporalDateLike).
+features: [Temporal]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+let yearMonth = new Temporal.PlainYearMonth(1999, 6);
+assert.sameValue(
+ cal.monthCode(yearMonth),
+ "M06",
+ 'cal.monthCode(new Temporal.PlainYearMonth(1999, 6)) must return "M06"'
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/year-zero.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/year-zero.js
new file mode 100644
index 0000000000..9a7df06b6c
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthCode/year-zero.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthcode
+description: Negative zero, as an extended year, is rejected
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ "-000000-10-31",
+ "-000000-10-31T00:45",
+ "-000000-10-31T00:45+01:00",
+ "-000000-10-31T00:45+00:00[UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.monthCode(arg),
+ "reject minus zero as extended year"
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/basic.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/basic.js
new file mode 100644
index 0000000000..09ca1c9b00
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/basic.js
@@ -0,0 +1,51 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthdayfromfields
+description: Temporal.Calendar.prototype.monthDayFromFields will return correctly with valid data.
+info: |
+ 1. Let calendar be the this value.
+ 2. Perform ? RequireInternalSlot(calendar, [[InitializedTemporalCalendar]]).
+ 3. Assert: calendar.[[Identifier]] is "iso8601".
+ 4. If Type(fields) is not Object, throw a TypeError exception.
+ 5. Set options to ? GetOptionsObject(options).
+ 6. Set fields to ? PrepareTemporalFields(fields, « "day", "month", "monthCode", "year" », « "day" »).
+ 7. Let overflow be ? ToTemporalOverflow(options).
+ 8. Perform ? ISOResolveMonth(fields).
+ 9. Let result be ? ISOMonthDayFromFields(fields, overflow).
+ 10. Return ? CreateTemporalMonthDay(result.[[Month]], result.[[Day]], "iso8601", result.[[ReferenceISOYear]]).
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const cal = new Temporal.Calendar("iso8601");
+
+const options = [
+ { overflow: "constrain" },
+ { overflow: "reject" },
+ {},
+ undefined,
+];
+options.forEach((opt) => {
+ const optionsDesc = opt && JSON.stringify(opt);
+ result = cal.monthDayFromFields({ year: 2021, month: 7, day: 3 }, opt);
+ TemporalHelpers.assertPlainMonthDay(result, "M07", 3, `month 7, day 3, with year, options = ${optionsDesc}`);
+ result = cal.monthDayFromFields({ year: 2021, month: 12, day: 31 }, opt);
+ TemporalHelpers.assertPlainMonthDay(result, "M12", 31, `month 12, day 31, with year, options = ${optionsDesc}`);
+ result = cal.monthDayFromFields({ monthCode: "M07", day: 3 }, opt);
+ TemporalHelpers.assertPlainMonthDay(result, "M07", 3, `monthCode M07, day 3, options = ${optionsDesc}`);
+ result = cal.monthDayFromFields({ monthCode: "M12", day: 31 }, opt);
+ TemporalHelpers.assertPlainMonthDay(result, "M12", 31, `monthCode M12, day 31, options = ${optionsDesc}`);
+});
+
+TemporalHelpers.ISOMonths.forEach(({ month, monthCode, daysInMonth }) => {
+ result = cal.monthDayFromFields({ month, day: daysInMonth });
+ TemporalHelpers.assertPlainMonthDay(result, monthCode, daysInMonth, `month ${month}, day ${daysInMonth}`);
+
+ result = cal.monthDayFromFields({ monthCode, day: daysInMonth });
+ TemporalHelpers.assertPlainMonthDay(result, monthCode, daysInMonth, `monthCode ${monthCode}, day ${daysInMonth}`);
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/branding.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/branding.js
new file mode 100644
index 0000000000..3fe68f7011
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/branding.js
@@ -0,0 +1,27 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthdayfromfields
+description: Throw a TypeError if the receiver is invalid
+features: [Symbol, Temporal]
+---*/
+
+const monthDayFromFields = Temporal.Calendar.prototype.monthDayFromFields;
+
+assert.sameValue(typeof monthDayFromFields, "function");
+
+const args = [{ monthCode: "M01", day: 1 }];
+
+assert.throws(TypeError, () => monthDayFromFields.apply(undefined, args), "undefined");
+assert.throws(TypeError, () => monthDayFromFields.apply(null, args), "null");
+assert.throws(TypeError, () => monthDayFromFields.apply(true, args), "true");
+assert.throws(TypeError, () => monthDayFromFields.apply("", args), "empty string");
+assert.throws(TypeError, () => monthDayFromFields.apply(Symbol(), args), "symbol");
+assert.throws(TypeError, () => monthDayFromFields.apply(1, args), "1");
+assert.throws(TypeError, () => monthDayFromFields.apply({}, args), "plain object");
+assert.throws(TypeError, () => monthDayFromFields.apply(Temporal.Calendar, args), "Temporal.Calendar");
+assert.throws(TypeError, () => monthDayFromFields.apply(Temporal.Calendar.prototype, args), "Temporal.Calendar.prototype");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/browser.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/browser.js
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/builtin.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/builtin.js
new file mode 100644
index 0000000000..0928552344
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/builtin.js
@@ -0,0 +1,36 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthdayfromfields
+description: >
+ Tests that Temporal.Calendar.prototype.monthDayFromFields
+ meets the requirements for built-in objects defined by the
+ introduction of chapter 17 of the ECMAScript Language Specification.
+info: |
+ Built-in functions that are not constructors do not have a "prototype" property unless
+ otherwise specified in the description of a particular function.
+
+ Unless specified otherwise, a built-in object that is callable as a function is a built-in
+ function object with the characteristics described in 10.3. Unless specified otherwise, the
+ [[Extensible]] internal slot of a built-in object initially has the value true.
+
+ Unless otherwise specified every built-in function and every built-in constructor has the
+ Function prototype object [...] as the value of its [[Prototype]] internal slot.
+features: [Temporal]
+---*/
+
+assert.sameValue(Object.isExtensible(Temporal.Calendar.prototype.monthDayFromFields),
+ true, "Built-in objects must be extensible.");
+
+assert.sameValue(Object.prototype.toString.call(Temporal.Calendar.prototype.monthDayFromFields),
+ "[object Function]", "Object.prototype.toString");
+
+assert.sameValue(Object.getPrototypeOf(Temporal.Calendar.prototype.monthDayFromFields),
+ Function.prototype, "prototype");
+
+assert.sameValue(Temporal.Calendar.prototype.monthDayFromFields.hasOwnProperty("prototype"),
+ false, "prototype property");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/fields-missing-properties.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/fields-missing-properties.js
new file mode 100644
index 0000000000..12ca8c5475
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/fields-missing-properties.js
@@ -0,0 +1,31 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthdayfromfields
+description: Temporal.Calendar.prototype.monthDayFromFields will throw TypeError with incorrect input data type.
+info: |
+ 1. Let calendar be the this value.
+ 2. Perform ? RequireInternalSlot(calendar, [[InitializedTemporalCalendar]]).
+ 3. Assert: calendar.[[Identifier]] is "iso8601".
+ 4. If Type(fields) is not Object, throw a TypeError exception.
+ 5. Set options to ? GetOptionsObject(options).
+ 6. Set fields to ? PrepareTemporalFields(fields, « "day", "month", "monthCode", "year" », « "day" »).
+ 7. Let overflow be ? ToTemporalOverflow(options).
+ 8. Perform ? ISOResolveMonth(fields).
+ 9. Let result be ? ISOMonthDayFromFields(fields, overflow).
+ 10. Return ? CreateTemporalMonthDay(result.[[Month]], result.[[Day]], "iso8601", result.[[ReferenceISOYear]]).
+features: [Temporal]
+---*/
+
+let cal = new Temporal.Calendar("iso8601")
+
+assert.throws(TypeError, () => cal.monthDayFromFields({}), "at least one correctly spelled property is required");
+assert.throws(TypeError, () => cal.monthDayFromFields({ month: 12 }), "day is required with month");
+assert.throws(TypeError, () => cal.monthDayFromFields({ monthCode: "M12" }), "day is required with monthCode");
+assert.throws(TypeError, () => cal.monthDayFromFields({ year: 2021, month: 12 }), "day is required with year and month");
+assert.throws(TypeError, () => cal.monthDayFromFields({ year: 2021, monthCode: "M12" }), "day is required with year and monthCode");
+assert.throws(TypeError, () => cal.monthDayFromFields({ year: 2021, day: 17 }), "either month or monthCode is required");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/fields-not-object.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/fields-not-object.js
new file mode 100644
index 0000000000..77991bbcef
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/fields-not-object.js
@@ -0,0 +1,17 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthdayfromfields
+description: Throw a TypeError if the fields is not an object
+features: [Symbol, Temporal]
+---*/
+
+const tests = [undefined, null, true, false, "string", Symbol("sym"), Math.PI, Infinity, NaN, 42n];
+const iso = Temporal.Calendar.from("iso8601");
+for (const fields of tests) {
+ assert.throws(TypeError, () => iso.monthDayFromFields(fields, {}));
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/infinity-throws-rangeerror.js
new file mode 100644
index 0000000000..b07372e0a7
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/infinity-throws-rangeerror.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: Throws if any value in the property bag is Infinity or -Infinity
+esid: sec-temporal.calendar.prototype.monthdayfromfields
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+const base = { year: 2000, month: 5, day: 2 };
+
+[Infinity, -Infinity].forEach((inf) => {
+ ["year", "month", "day"].forEach((prop) => {
+ ["constrain", "reject"].forEach((overflow) => {
+ assert.throws(RangeError, () => instance.monthDayFromFields({ ...base, [prop]: inf }, { overflow }), `${prop} property cannot be ${inf} (overflow ${overflow}`);
+
+ const calls = [];
+ const obj = TemporalHelpers.toPrimitiveObserver(calls, inf, prop);
+ assert.throws(RangeError, () => instance.monthDayFromFields({ ...base, [prop]: obj }, { overflow }));
+ assert.compareArray(calls, [`get ${prop}.valueOf`, `call ${prop}.valueOf`], "it fails after fetching the primitive value");
+ });
+ });
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/length.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/length.js
new file mode 100644
index 0000000000..ab0bc26c02
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/length.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2020 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthdayfromfields
+description: Temporal.Calendar.prototype.monthDayFromFields.length is 1
+info: |
+ Every built-in function object, including constructors, has a "length" property whose value is
+ an integer. Unless otherwise specified, this value is equal to the largest number of named
+ arguments shown in the subclause headings for the function description. Optional parameters
+ (which are indicated with brackets: [ ]) or rest parameters (which are shown using the form
+ «...name») are not included in the default argument count.
+
+ Unless otherwise specified, the "length" property of a built-in function object has the
+ attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+verifyProperty(Temporal.Calendar.prototype.monthDayFromFields, "length", {
+ value: 1,
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/missing-properties.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/missing-properties.js
new file mode 100644
index 0000000000..85331cb3d5
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/missing-properties.js
@@ -0,0 +1,39 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthdayfromfields
+description: Errors due to missing properties on fields object are thrown in the correct order
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const missingDay = {
+ get year() {
+ TemporalHelpers.assertUnreachable("day should be checked first");
+ },
+ get month() {
+ TemporalHelpers.assertUnreachable("day should be checked first");
+ },
+ get monthCode() {
+ TemporalHelpers.assertUnreachable("day should be checked first");
+ },
+};
+assert.throws(TypeError, () => instance.monthDayFromFields(missingDay), "day should be checked before year and month");
+
+let got = [];
+const fieldsSpy = TemporalHelpers.propertyBagObserver(got, { day: 1 });
+assert.throws(TypeError, () => instance.monthDayFromFields(fieldsSpy), "incomplete fields should be rejected (but after reading all non-required fields)");
+assert.compareArray(got, [
+ "get day",
+ "get day.valueOf",
+ "call day.valueOf",
+ "get month",
+ "get monthCode",
+ "get year",
+], "fields should be read in alphabetical order");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/monthcode-invalid.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/monthcode-invalid.js
new file mode 100644
index 0000000000..04424ff5c4
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/monthcode-invalid.js
@@ -0,0 +1,34 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthdayfromfields
+description: Throw RangeError for an out-of-range, conflicting, or ill-formed monthCode
+info: |
+ 1. Let calendar be the this value.
+ 2. Perform ? RequireInternalSlot(calendar, [[InitializedTemporalCalendar]]).
+ 3. Assert: calendar.[[Identifier]] is "iso8601".
+ 4. If Type(fields) is not Object, throw a TypeError exception.
+ 5. Set options to ? GetOptionsObject(options).
+ 6. Let result be ? ISOMonthDayFromFields(fields, options).
+ 7. Return ? CreateTemporalMonthDay(result.[[Month]], result.[[Day]], calendar, result.[[ReferenceISOYear]]).
+features: [Temporal]
+---*/
+
+const cal = new Temporal.Calendar("iso8601");
+
+["m1", "M1", "m01"].forEach((monthCode) => {
+ assert.throws(RangeError, () => cal.monthDayFromFields({ monthCode, day: 17 }),
+ `monthCode '${monthCode}' is not well-formed`);
+});
+
+assert.throws(RangeError, () => cal.monthDayFromFields({ year: 2021, month: 12, monthCode: "M11", day: 17 }),
+ "monthCode and month conflict");
+
+["M00", "M19", "M99", "M13"].forEach((monthCode) => {
+ assert.throws(RangeError, () => cal.monthDayFromFields({ monthCode, day: 17 }),
+ `monthCode '${monthCode}' is not valid for ISO 8601 calendar`);
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/name.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/name.js
new file mode 100644
index 0000000000..116caa43cd
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/name.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthdayfromfields
+description: Temporal.Calendar.prototype.monthDayFromFields.name is "monthDayFromFields".
+info: |
+ Every built-in function object, including constructors, that is not identified as an anonymous
+ function has a "name" property whose value is a String. Unless otherwise specified, this value
+ is the name that is given to the function in this specification.
+
+ Unless otherwise specified, the "name" property of a built-in function object, if it exists,
+ has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+verifyProperty(Temporal.Calendar.prototype.monthDayFromFields, "name", {
+ value: "monthDayFromFields",
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/not-a-constructor.js
new file mode 100644
index 0000000000..a9950ff3e3
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/not-a-constructor.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthdayfromfields
+description: >
+ Temporal.Calendar.prototype.monthDayFromFields does not implement [[Construct]], is not new-able
+info: |
+ Built-in function objects that are not identified as constructors do not implement the
+ [[Construct]] internal method unless otherwise specified in the description of a particular
+ function.
+includes: [isConstructor.js]
+features: [Reflect.construct, Temporal]
+---*/
+
+assert.throws(TypeError, () => {
+ new Temporal.Calendar.prototype.monthDayFromFields();
+}, "Calling as constructor");
+
+assert.sameValue(isConstructor(Temporal.Calendar.prototype.monthDayFromFields), false,
+ "isConstructor(Temporal.Calendar.prototype.monthDayFromFields)");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/one-of-era-erayear-undefined.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/one-of-era-erayear-undefined.js
new file mode 100644
index 0000000000..bc8f5b6f27
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/one-of-era-erayear-undefined.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthDayFromFields
+description: Does not throw a RangeError if only one of era/eraYear fields is present
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+const base = { year: 2000, month: 5, day: 2, era: 'ce' };
+const instance = new Temporal.Calendar('iso8601');
+TemporalHelpers.assertPlainMonthDay(instance.monthDayFromFields({ ...base }), 'M05', 2);
+
+const base2 = { year: 2000, month: 5, day: 2, eraYear: 1 };
+TemporalHelpers.assertPlainMonthDay(instance.monthDayFromFields({ ...base }), 'M05', 2);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/options-object.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/options-object.js
new file mode 100644
index 0000000000..277bec6757
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/options-object.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthdayfromfields
+description: Empty or a function object may be used as options
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const result1 = instance.monthDayFromFields({ monthCode: "M12", day: 15 }, {});
+TemporalHelpers.assertPlainMonthDay(
+ result1, "M12", 15,
+ "options may be an empty plain object"
+);
+
+const result2 = instance.monthDayFromFields({ monthCode: "M12", day: 15 }, () => {});
+TemporalHelpers.assertPlainMonthDay(
+ result2, "M12", 15,
+ "options may be a function object"
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/options-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/options-wrong-type.js
new file mode 100644
index 0000000000..4ffb442486
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/options-wrong-type.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthdayfromfields
+description: TypeError thrown when options argument is a primitive
+features: [BigInt, Symbol, Temporal]
+---*/
+
+const badOptions = [
+ null,
+ true,
+ "some string",
+ Symbol(),
+ 1,
+ 2n,
+];
+
+const instance = new Temporal.Calendar("iso8601");
+for (const value of badOptions) {
+ assert.throws(TypeError, () => instance.monthDayFromFields({ monthCode: "M12", day: 15 }, value),
+ `TypeError on wrong options type ${typeof value}`);
+};
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/order-of-operations.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/order-of-operations.js
new file mode 100644
index 0000000000..e7e7458af8
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/order-of-operations.js
@@ -0,0 +1,49 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthdayfromfields
+description: Properties on objects passed to monthDayFromFields() are accessed in the correct order
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const expected = [
+ "get fields.day",
+ "get fields.day.valueOf",
+ "call fields.day.valueOf",
+ "get fields.month",
+ "get fields.month.valueOf",
+ "call fields.month.valueOf",
+ "get fields.monthCode",
+ "get fields.monthCode.toString",
+ "call fields.monthCode.toString",
+ "get fields.year",
+ "get fields.year.valueOf",
+ "call fields.year.valueOf",
+ "get options.overflow",
+ "get options.overflow.toString",
+ "call options.overflow.toString",
+];
+const actual = [];
+
+const instance = new Temporal.Calendar("iso8601");
+
+const fields = TemporalHelpers.propertyBagObserver(actual, {
+ year: 1.7,
+ month: 1.7,
+ monthCode: "M01",
+ day: 1.7,
+}, "fields");
+
+const options = TemporalHelpers.propertyBagObserver(actual, {
+ overflow: "reject",
+}, "options");
+
+const result = instance.monthDayFromFields(fields, options);
+TemporalHelpers.assertPlainMonthDay(result, "M01", 1, "monthDay result");
+assert.sameValue(result.getISOFields().calendar, "iso8601", "calendar slot should store a string");
+assert.compareArray(actual, expected, "order of operations");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/overflow-constrain.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/overflow-constrain.js
new file mode 100644
index 0000000000..072e99e3f7
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/overflow-constrain.js
@@ -0,0 +1,68 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthdayfromfields
+description: Temporal.Calendar.prototype.monthDayFromFields will return correctly with data and overflow set to 'constrain'.
+info: |
+ 1. Let calendar be the this value.
+ 2. Perform ? RequireInternalSlot(calendar, [[InitializedTemporalCalendar]]).
+ 3. Assert: calendar.[[Identifier]] is "iso8601".
+ 4. If Type(fields) is not Object, throw a TypeError exception.
+ 5. Set options to ? GetOptionsObject(options).
+ 6. Set fields to ? PrepareTemporalFields(fields, « "day", "month", "monthCode", "year" », « "day" »).
+ 7. Let overflow be ? ToTemporalOverflow(options).
+ 8. Perform ? ISOResolveMonth(fields).
+ 9. Let result be ? ISOMonthDayFromFields(fields, overflow).
+ 10. Return ? CreateTemporalMonthDay(result.[[Month]], result.[[Day]], "iso8601", result.[[ReferenceISOYear]]).
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const cal = new Temporal.Calendar("iso8601");
+const opt = { overflow: "constrain" };
+
+let result = cal.monthDayFromFields({ year: 2021, month: 13, day: 1 }, opt);
+TemporalHelpers.assertPlainMonthDay(result, "M12", 1, "month 13 is constrained to 12");
+
+result = cal.monthDayFromFields({ year: 2021, month: 999999, day: 500 }, opt);
+TemporalHelpers.assertPlainMonthDay(result, "M12", 31, "month 999999 is constrained to 12 and day 500 is constrained to 31");
+
+[-99999, -1, 0].forEach((month) => {
+ assert.throws(
+ RangeError,
+ () => cal.monthDayFromFields({ year: 2021, month, day: 1 }, opt),
+ `Month ${month} is out of range for 2021 even with overflow: constrain`
+ );
+});
+
+TemporalHelpers.ISOMonths.forEach(({ month, monthCode, daysInMonth }) => {
+ const day = daysInMonth + 1;
+
+ result = cal.monthDayFromFields({ month, day }, opt);
+ TemporalHelpers.assertPlainMonthDay(result, monthCode, daysInMonth,
+ `day is constrained from ${day} to ${daysInMonth} in month ${month}`);
+
+ result = cal.monthDayFromFields({ month, day: 9001 }, opt);
+ TemporalHelpers.assertPlainMonthDay(result, monthCode, daysInMonth,
+ `day is constrained to ${daysInMonth} in month ${month}`);
+
+ result = cal.monthDayFromFields({ monthCode, day }, opt);
+ TemporalHelpers.assertPlainMonthDay(result, monthCode, daysInMonth,
+ `day is constrained from ${day} to ${daysInMonth} in monthCode ${monthCode}`);
+
+ result = cal.monthDayFromFields({ monthCode, day: 9001 }, opt);
+ TemporalHelpers.assertPlainMonthDay(result, monthCode, daysInMonth,
+ `day is constrained to ${daysInMonth} in monthCode ${monthCode}`);
+});
+
+[ ["month", 2], ["monthCode", "M02"] ].forEach(([ name, value ]) => {
+ result = cal.monthDayFromFields({ year: 2020, [name]: value, day: 30 }, opt);
+ TemporalHelpers.assertPlainMonthDay(result, "M02", 29, `${name} ${value} is constrained to 29 in leap year 2020`);
+
+ result = cal.monthDayFromFields({ year: 2021, [name]: value, day: 29 }, opt);
+ TemporalHelpers.assertPlainMonthDay(result, "M02", 28, `${name} ${value} is constrained to 28 in common year 2021`);
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/overflow-invalid-string.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/overflow-invalid-string.js
new file mode 100644
index 0000000000..b028e3fdfc
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/overflow-invalid-string.js
@@ -0,0 +1,30 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthdayfromfields
+description: RangeError thrown when overflow option not one of the allowed string values
+info: |
+ sec-getoption step 10:
+ 10. If _values_ is not *undefined* and _values_ does not contain an element equal to _value_, throw a *RangeError* exception.
+ sec-temporal-totemporaloverflow step 1:
+ 1. Return ? GetOption(_normalizedOptions_, *"overflow"*, « String », « *"constrain"*, *"reject"* », *"constrain"*).
+ sec-temporal-isomonthdayfromfields step 2:
+ 2. Let _overflow_ be ? ToTemporalOverflow(_options_).
+ sec-temporal.calendar.prototype.monthdayfromfields step 6:
+ 6. Let _result_ be ? ISOMonthDayFromFields(_fields_, _options_).
+features: [Temporal]
+---*/
+
+const calendar = new Temporal.Calendar("iso8601");
+const badOverflows = ["", "CONSTRAIN", "balance", "other string", "constra\u0131n", "reject\0"];
+for (const overflow of badOverflows) {
+ assert.throws(
+ RangeError,
+ () => calendar.monthDayFromFields({ year: 2000, month: 5, day: 2 }, { overflow }),
+ `invalid overflow ("${overflow}")`
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/overflow-reject.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/overflow-reject.js
new file mode 100644
index 0000000000..fbc8f9351a
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/overflow-reject.js
@@ -0,0 +1,65 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthdayfromfields
+description: Throw RangeError for input data out of range with overflow reject
+info: |
+ 1. Let calendar be the this value.
+ 2. Perform ? RequireInternalSlot(calendar, [[InitializedTemporalCalendar]]).
+ 3. Assert: calendar.[[Identifier]] is "iso8601".
+ 4. If Type(fields) is not Object, throw a TypeError exception.
+ 5. Set options to ? GetOptionsObject(options).
+ 6. Set fields to ? PrepareTemporalFields(fields, « "day", "month", "monthCode", "year" », « "day" »).
+ 7. Let overflow be ? ToTemporalOverflow(options).
+ 8. Perform ? ISOResolveMonth(fields).
+ 9. Let result be ? ISOMonthDayFromFields(fields, overflow).
+ 10. Return ? CreateTemporalMonthDay(result.[[Month]], result.[[Day]], "iso8601", result.[[ReferenceISOYear]]).
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const cal = new Temporal.Calendar("iso8601");
+
+[-1, 0, 13, 9995].forEach((month) => {
+ assert.throws(
+ RangeError,
+ () => cal.monthDayFromFields({year: 2021, month, day: 5}, { overflow: "reject" }),
+ `Month ${month} is out of range for 2021 with overflow: reject`
+ );
+});
+
+[-1, 0, 32, 999].forEach((day) => {
+ assert.throws(
+ RangeError,
+ () => cal.monthDayFromFields({ year: 2021, month: 12, day }, { overflow: "reject" }),
+ `Day ${day} is out of range for 2021-12 with overflow: reject`
+ );
+ assert.throws(
+ RangeError,
+ () => cal.monthDayFromFields({ monthCode: "M12", day }, { overflow: "reject" }),
+ `Day ${day} is out of range for 2021-M12 with overflow: reject`
+ );
+});
+
+TemporalHelpers.ISOMonths.forEach(({ month, monthCode, daysInMonth }) => {
+ const day = daysInMonth + 1;
+ assert.throws(RangeError,
+ () => cal.monthDayFromFields({ month, day }, { overflow: "reject" }),
+ `Day ${day} is out of range for month ${month} with overflow: reject`);
+ assert.throws(RangeError,
+ () => cal.monthDayFromFields({ monthCode, day }, { overflow: "reject" }),
+ `Day ${day} is out of range for monthCode ${monthCode} with overflow: reject`);
+});
+
+[ ["month", 2], ["monthCode", "M02"] ].forEach(([ name, value ]) => {
+ assert.throws(RangeError,
+ () => cal.monthDayFromFields({ year: 2020, [name]: value, day: 30 }, { overflow: "reject" }),
+ `Day 30 is out of range for ${name} ${value} in leap year 2020 with overflow: reject`);
+ assert.throws(RangeError,
+ () => cal.monthDayFromFields({ year: 2021, [name]: value, day: 29 }, { overflow: "reject" }),
+ `Day 29 is out of range for ${name} ${value} in common year 2021 with overflow: reject`);
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/overflow-undefined.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/overflow-undefined.js
new file mode 100644
index 0000000000..a44b81623e
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/overflow-undefined.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthdayfromfields
+description: Fallback value for overflow option
+info: |
+ sec-getoption step 3:
+ 3. If _value_ is *undefined*, return _fallback_.
+ sec-temporal-totemporaloverflow step 1:
+ 1. Return ? GetOption(_normalizedOptions_, *"overflow"*, « String », « *"constrain"*, *"reject"* », *"constrain"*).
+ sec-temporal-isomonthdayfromfields step 2:
+ 2. Let _overflow_ be ? ToTemporalOverflow(_options_).
+ sec-temporal.calendar.prototype.monthdayfromfields step 6:
+ 6. Let _result_ be ? ISOMonthDayFromFields(_fields_, _options_).
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = new Temporal.Calendar("iso8601");
+
+const explicit = calendar.monthDayFromFields({ year: 2000, month: 15, day: 2 }, { overflow: undefined });
+TemporalHelpers.assertPlainMonthDay(explicit, "M12", 2, "default overflow is constrain");
+const implicit = calendar.monthDayFromFields({ year: 2000, month: 15, day: 2 }, {});
+TemporalHelpers.assertPlainMonthDay(implicit, "M12", 2, "default overflow is constrain");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/overflow-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/overflow-wrong-type.js
new file mode 100644
index 0000000000..bd1622c3c8
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/overflow-wrong-type.js
@@ -0,0 +1,27 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthdayfromfields
+description: Type conversions for overflow option
+info: |
+ sec-getoption step 9.a:
+ a. Set _value_ to ? ToString(_value_).
+ sec-temporal-totemporaloverflow step 1:
+ 1. Return ? GetOption(_normalizedOptions_, *"overflow"*, « String », « *"constrain"*, *"reject"* », *"constrain"*).
+ sec-temporal-isomonthdayfromfields step 2:
+ 2. Let _overflow_ be ? ToTemporalOverflow(_options_).
+ sec-temporal.calendar.prototype.monthdayfromfields step 6:
+ 6. Let _result_ be ? ISOMonthDayFromFields(_fields_, _options_).
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = new Temporal.Calendar("iso8601");
+TemporalHelpers.checkStringOptionWrongType("overflow", "constrain",
+ (overflow) => calendar.monthDayFromFields({ year: 2000, month: 5, day: 2 }, { overflow }),
+ (result, descr) => TemporalHelpers.assertPlainMonthDay(result, "M05", 2, descr),
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/prop-desc.js
new file mode 100644
index 0000000000..f19dfbb6b5
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/prop-desc.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthdayfromfields
+description: The "monthDayFromFields" property of Temporal.Calendar.prototype
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+assert.sameValue(
+ typeof Temporal.Calendar.prototype.monthDayFromFields,
+ "function",
+ "`typeof Calendar.prototype.monthDayFromFields` is `function`"
+);
+
+verifyProperty(Temporal.Calendar.prototype, "monthDayFromFields", {
+ writable: true,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/shell.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/shell.js
new file mode 100644
index 0000000000..eda1477282
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthDayFromFields/shell.js
@@ -0,0 +1,24 @@
+// GENERATED, DO NOT EDIT
+// file: isConstructor.js
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: |
+ Test if a given function is a constructor function.
+defines: [isConstructor]
+features: [Reflect.construct]
+---*/
+
+function isConstructor(f) {
+ if (typeof f !== "function") {
+ throw new Test262Error("isConstructor invoked with a non-function value");
+ }
+
+ try {
+ Reflect.construct(function(){}, [], f);
+ } catch (e) {
+ return false;
+ }
+ return true;
+}
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-builtin-calendar-no-array-iteration.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-builtin-calendar-no-array-iteration.js
new file mode 100644
index 0000000000..35c86dbff2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-builtin-calendar-no-array-iteration.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthsinyear
+description: >
+ Calling the method with a property bag argument with a builtin calendar causes
+ no observable array iteration when getting the calendar fields.
+features: [Temporal]
+---*/
+
+const arrayPrototypeSymbolIteratorOriginal = Array.prototype[Symbol.iterator];
+Array.prototype[Symbol.iterator] = function arrayIterator() {
+ throw new Test262Error("Array should not be iterated");
+}
+
+const instance = new Temporal.Calendar("iso8601");
+const arg = { year: 2000, month: 5, day: 2, calendar: "iso8601" };
+instance.monthsInYear(arg);
+
+Array.prototype[Symbol.iterator] = arrayPrototypeSymbolIteratorOriginal;
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-calendar-datefromfields-called-with-null-prototype-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-calendar-datefromfields-called-with-null-prototype-fields.js
new file mode 100644
index 0000000000..6f6e691a59
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-calendar-datefromfields-called-with-null-prototype-fields.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthsinyear
+description: >
+ Calendar.dateFromFields method is called with a null-prototype fields object
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarCheckFieldsPrototypePollution();
+const instance = new Temporal.Calendar("iso8601");
+const arg = { year: 2000, month: 5, day: 2, calendar };
+instance.monthsInYear(arg);
+assert.sameValue(calendar.dateFromFieldsCallCount, 1, "dateFromFields should be called on the property bag's calendar");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-constructor-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-constructor-in-calendar-fields.js
new file mode 100644
index 0000000000..2fca9d4da2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-constructor-in-calendar-fields.js
@@ -0,0 +1,17 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.monthsinyear
+description: If a calendar's fields() method returns a field named 'constructor', PrepareTemporalFields should throw a RangeError.
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarWithExtraFields(['constructor']);
+const arg = {year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar};
+const instance = new Temporal.Calendar("iso8601");
+
+assert.throws(RangeError, () => instance.monthsInYear(arg));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-duplicate-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-duplicate-calendar-fields.js
new file mode 100644
index 0000000000..f6da9031af
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-duplicate-calendar-fields.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.monthsinyear
+description: If a calendar's fields() method returns duplicate field names, PrepareTemporalFields should throw a RangeError.
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+for (const extra_fields of [['foo', 'foo'], ['day'], ['month'], ['monthCode'], ['year']]) {
+ const calendar = TemporalHelpers.calendarWithExtraFields(extra_fields);
+ const arg = { year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar };
+ const instance = new Temporal.Calendar("iso8601");
+
+ assert.throws(RangeError, () => instance.monthsInYear(arg));
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-leap-second.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-leap-second.js
new file mode 100644
index 0000000000..ff7496e9b1
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-leap-second.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthsinyear
+description: Leap second is a valid ISO string for PlainDate
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+let arg = "2016-12-31T23:59:60";
+const result1 = instance.monthsInYear(arg);
+assert.sameValue(
+ result1,
+ 12,
+ "leap second is a valid ISO string for PlainDate"
+);
+
+arg = { year: 2016, month: 12, day: 31, hour: 23, minute: 59, second: 60 };
+const result2 = instance.monthsInYear(arg);
+assert.sameValue(
+ result2,
+ 12,
+ "second: 60 is ignored in property bag for PlainDate"
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-number.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-number.js
new file mode 100644
index 0000000000..2a99f73f8b
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-number.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthsinyear
+description: A number cannot be used in place of a Temporal.PlainDate
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const numbers = [
+ 1,
+ 19761118,
+ -19761118,
+ 1234567890,
+];
+
+for (const arg of numbers) {
+ assert.throws(
+ TypeError,
+ () => instance.monthsInYear(arg),
+ 'Numbers cannot be used in place of an ISO string for PlainDate'
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-propertybag-calendar-case-insensitive.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-propertybag-calendar-case-insensitive.js
new file mode 100644
index 0000000000..b8ee4e933b
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-propertybag-calendar-case-insensitive.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthsinyear
+description: The calendar name is case-insensitive
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const calendar = "IsO8601";
+
+const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+const result = instance.monthsInYear(arg);
+assert.sameValue(result, 12, "Calendar is case-insensitive");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-propertybag-calendar-leap-second.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-propertybag-calendar-leap-second.js
new file mode 100644
index 0000000000..0d6c0d6ef4
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-propertybag-calendar-leap-second.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthsinyear
+description: Leap second is a valid ISO string for a calendar in a property bag
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const calendar = "2016-12-31T23:59:60";
+
+const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+const result = instance.monthsInYear(arg);
+assert.sameValue(
+ result,
+ 12,
+ "leap second is a valid ISO string for calendar"
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-propertybag-calendar-number.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-propertybag-calendar-number.js
new file mode 100644
index 0000000000..a0f70626e5
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-propertybag-calendar-number.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthsinyear
+description: A number as calendar in a property bag is not accepted
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const numbers = [
+ 1,
+ 19970327,
+ -19970327,
+ 1234567890,
+];
+
+for (const calendar of numbers) {
+ const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+ assert.throws(
+ TypeError,
+ () => instance.monthsInYear(arg),
+ "Numbers cannot be used as a calendar"
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-propertybag-calendar-string.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-propertybag-calendar-string.js
new file mode 100644
index 0000000000..460a47804c
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-propertybag-calendar-string.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthsinyear
+description: A calendar ID is valid input for Calendar
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const calendar = "iso8601";
+
+const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+const result = instance.monthsInYear(arg);
+assert.sameValue(result, 12, `Calendar created from string "${calendar}"`);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-propertybag-calendar-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-propertybag-calendar-wrong-type.js
new file mode 100644
index 0000000000..2b01fe1a0e
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-propertybag-calendar-wrong-type.js
@@ -0,0 +1,46 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthsinyear
+description: >
+ Appropriate error thrown when a calendar property from a property bag cannot
+ be converted to a calendar object or string
+features: [BigInt, Symbol, Temporal]
+---*/
+
+const timeZone = new Temporal.TimeZone("UTC");
+const instance = new Temporal.Calendar("iso8601");
+
+const primitiveTests = [
+ [null, "null"],
+ [true, "boolean"],
+ ["", "empty string"],
+ [1, "number that doesn't convert to a valid ISO string"],
+ [1n, "bigint"],
+];
+
+for (const [calendar, description] of primitiveTests) {
+ const arg = { year: 2019, monthCode: "M11", day: 1, calendar };
+ assert.throws(
+ typeof calendar === 'string' ? RangeError : TypeError,
+ () => instance.monthsInYear(arg),
+ `${description} does not convert to a valid ISO string`
+ );
+}
+
+const typeErrorTests = [
+ [Symbol(), "symbol"],
+ [{}, "plain object that doesn't implement the protocol"],
+ [new Temporal.TimeZone("UTC"), "time zone instance"],
+ [Temporal.Calendar, "Temporal.Calendar, object"],
+ [Temporal.Calendar.prototype, "Temporal.Calendar.prototype, object"], // fails brand check in dateFromFields()
+];
+
+for (const [calendar, description] of typeErrorTests) {
+ const arg = { year: 2019, monthCode: "M11", day: 1, calendar };
+ assert.throws(TypeError, () => instance.monthsInYear(arg), `${description} is not a valid property bag and does not convert to a string`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-propertybag-calendar-year-zero.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-propertybag-calendar-year-zero.js
new file mode 100644
index 0000000000..c05540c245
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-propertybag-calendar-year-zero.js
@@ -0,0 +1,27 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthsinyear
+description: Negative zero, as an extended year, is rejected
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ "-000000-10-31",
+ "-000000-10-31T17:45",
+ "-000000-10-31T17:45Z",
+ "-000000-10-31T17:45+01:00",
+ "-000000-10-31T17:45+00:00[UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.monthsInYear(arg),
+ "reject minus zero as extended year"
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-proto-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-proto-in-calendar-fields.js
new file mode 100644
index 0000000000..0ee2a148c3
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-proto-in-calendar-fields.js
@@ -0,0 +1,17 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.monthsinyear
+description: If a calendar's fields() method returns a field named '__proto__', PrepareTemporalFields should throw a RangeError.
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarWithExtraFields(['__proto__']);
+const arg = {year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar};
+const instance = new Temporal.Calendar("iso8601");
+
+assert.throws(RangeError, () => instance.monthsInYear(arg));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string-calendar-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string-calendar-annotation.js
new file mode 100644
index 0000000000..3612b56cf3
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string-calendar-annotation.js
@@ -0,0 +1,33 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthsinyear
+description: Various forms of calendar annotation; critical flag has no effect
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02[u-ca=iso8601]", "without time or time zone"],
+ ["2000-05-02[UTC][u-ca=iso8601]", "with time zone and no time"],
+ ["2000-05-02T15:23[u-ca=iso8601]", "without time zone"],
+ ["2000-05-02T15:23[UTC][u-ca=iso8601]", "with time zone"],
+ ["2000-05-02T15:23[!u-ca=iso8601]", "with ! and no time zone"],
+ ["2000-05-02T15:23[UTC][!u-ca=iso8601]", "with ! and time zone"],
+ ["2000-05-02T15:23[u-ca=iso8601][u-ca=discord]", "second annotation ignored"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.monthsInYear(arg);
+
+ assert.sameValue(
+ result,
+ 12,
+ `calendar annotation (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string-critical-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string-critical-unknown-annotation.js
new file mode 100644
index 0000000000..578dc6f78a
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string-critical-unknown-annotation.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthsinyear
+description: Unknown annotations with critical flag are rejected
+features: [Temporal]
+---*/
+
+const invalidStrings = [
+ "1970-01-01[!foo=bar]",
+ "1970-01-01T00:00[!foo=bar]",
+ "1970-01-01T00:00[UTC][!foo=bar]",
+ "1970-01-01T00:00[u-ca=iso8601][!foo=bar]",
+ "1970-01-01T00:00[UTC][!foo=bar][u-ca=iso8601]",
+ "1970-01-01T00:00[foo=bar][!_foo-bar0=Dont-Ignore-This-99999999999]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.monthsInYear(arg),
+ `reject unknown annotation with critical flag: ${arg}`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string-date-with-utc-offset.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string-date-with-utc-offset.js
new file mode 100644
index 0000000000..5b5536623f
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string-date-with-utc-offset.js
@@ -0,0 +1,48 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthsinyear
+description: UTC offset not valid with format that does not include a time
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const validStrings = [
+ "2000-05-02T00+00:00",
+ "2000-05-02T00+00:00[UTC]",
+ "2000-05-02T00+00:00[!UTC]",
+ "2000-05-02T00-02:30[America/St_Johns]",
+];
+
+for (const arg of validStrings) {
+ const result = instance.monthsInYear(arg);
+
+ assert.sameValue(
+ result,
+ 12,
+ `"${arg}" is a valid UTC offset with time for PlainDate`
+ );
+}
+
+const invalidStrings = [
+ "2022-09-15Z",
+ "2022-09-15Z[UTC]",
+ "2022-09-15Z[Europe/Vienna]",
+ "2022-09-15+00:00",
+ "2022-09-15+00:00[UTC]",
+ "2022-09-15-02:30",
+ "2022-09-15-02:30[America/St_Johns]",
+];
+
+for (const arg of invalidStrings) {
+ assert.throws(
+ RangeError,
+ () => instance.monthsInYear(arg),
+ `"${arg}" UTC offset without time is not valid for PlainDate`
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string-invalid.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string-invalid.js
new file mode 100644
index 0000000000..fc2949e0c5
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string-invalid.js
@@ -0,0 +1,64 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthsinyear
+description: >
+ RangeError thrown if an invalid ISO string (or syntactically valid ISO string
+ that is not supported) is used as a PlainDate
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ // invalid ISO strings:
+ "",
+ "invalid iso8601",
+ "2020-01-00",
+ "2020-01-32",
+ "2020-02-30",
+ "2021-02-29",
+ "2020-00-01",
+ "2020-13-01",
+ "2020-01-01T",
+ "2020-01-01T25:00:00",
+ "2020-01-01T01:60:00",
+ "2020-01-01T01:60:61",
+ "2020-01-01junk",
+ "2020-01-01T00:00:00junk",
+ "2020-01-01T00:00:00+00:00junk",
+ "2020-01-01T00:00:00+00:00[UTC]junk",
+ "2020-01-01T00:00:00+00:00[UTC][u-ca=iso8601]junk",
+ "02020-01-01",
+ "2020-001-01",
+ "2020-01-001",
+ "2020-01-01T001",
+ "2020-01-01T01:001",
+ "2020-01-01T01:01:001",
+ // valid, but forms not supported in Temporal:
+ "2020-W01-1",
+ "2020-001",
+ "+0002020-01-01",
+ // valid, but this calendar must not exist:
+ "2020-01-01[u-ca=notexist]",
+ // may be valid in other contexts, but insufficient information for PlainDate:
+ "2020-01",
+ "+002020-01",
+ "01-01",
+ "2020-W01",
+ "P1Y",
+ "-P12Y",
+ // valid, but outside the supported range:
+ "-999999-01-01",
+ "+999999-01-01",
+];
+const instance = new Temporal.Calendar("iso8601");
+for (const arg of invalidStrings) {
+ assert.throws(
+ RangeError,
+ () => instance.monthsInYear(arg),
+ `"${arg}" should not be a valid ISO string for a PlainDate`
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string-multiple-calendar.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string-multiple-calendar.js
new file mode 100644
index 0000000000..0be9d3322c
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string-multiple-calendar.js
@@ -0,0 +1,32 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthsinyear
+description: >
+ More than one calendar annotation is not syntactical if any have the criical
+ flag
+features: [Temporal]
+---*/
+
+const invalidStrings = [
+ "1970-01-01[u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01[!u-ca=iso8601][u-ca=iso8601]",
+ "1970-01-01[UTC][u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01[u-ca=iso8601][foo=bar][!u-ca=iso8601]",
+ "1970-01-01T00:00[u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01T00:00[!u-ca=iso8601][u-ca=iso8601]",
+ "1970-01-01T00:00[UTC][u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01T00:00[u-ca=iso8601][foo=bar][!u-ca=iso8601]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.monthsInYear(arg),
+ `reject more than one calendar annotation if any critical: ${arg}`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string-multiple-time-zone.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string-multiple-time-zone.js
new file mode 100644
index 0000000000..76d6a2889f
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string-multiple-time-zone.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthsinyear
+description: More than one time zone annotation is not syntactical
+features: [Temporal]
+---*/
+
+const invalidStrings = [
+ "1970-01-01[UTC][UTC]",
+ "1970-01-01T00:00[UTC][UTC]",
+ "1970-01-01T00:00[!UTC][UTC]",
+ "1970-01-01T00:00[UTC][!UTC]",
+ "1970-01-01T00:00[UTC][u-ca=iso8601][UTC]",
+ "1970-01-01T00:00[UTC][foo=bar][UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.monthsInYear(arg),
+ `reject more than one time zone annotation: ${arg}`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string-time-separators.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string-time-separators.js
new file mode 100644
index 0000000000..05b17c402e
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string-time-separators.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthsinyear
+description: Time separator in string argument can vary
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02T15:23", "uppercase T"],
+ ["2000-05-02t15:23", "lowercase T"],
+ ["2000-05-02 15:23", "space between date and time"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.monthsInYear(arg);
+
+ assert.sameValue(
+ result,
+ 12,
+ `variant time separators (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string-time-zone-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string-time-zone-annotation.js
new file mode 100644
index 0000000000..dd25899d21
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string-time-zone-annotation.js
@@ -0,0 +1,38 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthsinyear
+description: Various forms of time zone annotation; critical flag has no effect
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02[Asia/Kolkata]", "named, with no time"],
+ ["2000-05-02[!Europe/Vienna]", "named, with ! and no time"],
+ ["2000-05-02[+00:00]", "numeric, with no time"],
+ ["2000-05-02[!-02:30]", "numeric, with ! and no time"],
+ ["2000-05-02T15:23[America/Sao_Paulo]", "named, with no offset"],
+ ["2000-05-02T15:23[!Asia/Tokyo]", "named, with ! and no offset"],
+ ["2000-05-02T15:23[-02:30]", "numeric, with no offset"],
+ ["2000-05-02T15:23[!+00:00]", "numeric, with ! and no offset"],
+ ["2000-05-02T15:23+00:00[America/New_York]", "named, with offset"],
+ ["2000-05-02T15:23+00:00[!UTC]", "named, with offset and !"],
+ ["2000-05-02T15:23+00:00[+01:00]", "numeric, with offset"],
+ ["2000-05-02T15:23+00:00[!-08:00]", "numeric, with offset and !"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.monthsInYear(arg);
+
+ assert.sameValue(
+ result,
+ 12,
+ `time zone annotation (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string-unknown-annotation.js
new file mode 100644
index 0000000000..bb7b7ee3f2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string-unknown-annotation.js
@@ -0,0 +1,32 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthsinyear
+description: Various forms of unknown annotation
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02[foo=bar]", "without time"],
+ ["2000-05-02T15:23[foo=bar]", "alone"],
+ ["2000-05-02T15:23[UTC][foo=bar]", "with time zone"],
+ ["2000-05-02T15:23[u-ca=iso8601][foo=bar]", "with calendar"],
+ ["2000-05-02T15:23[UTC][foo=bar][u-ca=iso8601]", "with time zone and calendar"],
+ ["2000-05-02T15:23[foo=bar][_foo-bar0=Ignore-This-999999999999]", "with another unknown annotation"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.monthsInYear(arg);
+
+ assert.sameValue(
+ result,
+ 12,
+ `unknown annotation (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string-with-utc-designator.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string-with-utc-designator.js
new file mode 100644
index 0000000000..1d40c304b9
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string-with-utc-designator.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthsinyear
+description: RangeError thrown if a string with UTC designator is used as a PlainDate
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ "2019-10-01T09:00:00Z",
+ "2019-10-01T09:00:00Z[UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.monthsInYear(arg),
+ "String with UTC designator should not be valid as a PlainDate"
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string.js
new file mode 100644
index 0000000000..ef3a529db2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string.js
@@ -0,0 +1,21 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthsinyear
+description: An ISO 8601 date string should be converted as input
+info: |
+ a. Perform ? ToTemporalDate(temporalDateLike).
+ 5. Return 12𝔽.
+features: [Temporal]
+---*/
+
+let cal = new Temporal.Calendar("iso8601");
+
+assert.sameValue(cal.monthsInYear("3456-12-20"), 12);
+assert.sameValue(cal.monthsInYear("+000998-01-28"), 12);
+assert.sameValue(cal.monthsInYear("3456-12-20T03:04:05+00:00[UTC]"), 12);
+assert.sameValue(cal.monthsInYear("+000998-01-28T03:04:05+00:00[UTC]"), 12);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-wrong-type.js
new file mode 100644
index 0000000000..bbe7c6bec4
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-wrong-type.js
@@ -0,0 +1,43 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthsinyear
+description: >
+ Appropriate error thrown when argument cannot be converted to a valid string
+ or property bag for PlainDate
+features: [BigInt, Symbol, Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const primitiveTests = [
+ [undefined, "undefined"],
+ [null, "null"],
+ [true, "boolean"],
+ ["", "empty string"],
+ [1, "number that doesn't convert to a valid ISO string"],
+ [1n, "bigint"],
+];
+
+for (const [arg, description] of primitiveTests) {
+ assert.throws(
+ typeof arg === 'string' ? RangeError : TypeError,
+ () => instance.monthsInYear(arg),
+ `${description} does not convert to a valid ISO string`
+ );
+}
+
+const typeErrorTests = [
+ [Symbol(), "symbol"],
+ [{}, "plain object"],
+ [Temporal.PlainDate, "Temporal.PlainDate, object"],
+ [Temporal.PlainDate.prototype, "Temporal.PlainDate.prototype, object"],
+];
+
+for (const [arg, description] of typeErrorTests) {
+ assert.throws(TypeError, () => instance.monthsInYear(arg), `${description} is not a valid property bag and does not convert to a string`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-zoneddatetime-convert.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-zoneddatetime-convert.js
new file mode 100644
index 0000000000..63120471a8
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-zoneddatetime-convert.js
@@ -0,0 +1,22 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthsinyear
+description: An exception from TimeZone#getOffsetNanosecondsFor() is propagated.
+features: [Temporal]
+---*/
+
+class TZ extends Temporal.TimeZone {
+ constructor() { super("UTC") }
+ getOffsetNanosecondsFor() { throw new Test262Error() }
+}
+
+const tz = new TZ();
+const arg = new Temporal.ZonedDateTime(0n, tz);
+const instance = new Temporal.Calendar("iso8601");
+
+assert.throws(Test262Error, () => instance.monthsInYear(arg));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-zoneddatetime-slots.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-zoneddatetime-slots.js
new file mode 100644
index 0000000000..e937a035ca
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-zoneddatetime-slots.js
@@ -0,0 +1,40 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthsinyear
+description: Getters are not called when converting a ZonedDateTime to a PlainDate.
+includes: [compareArray.js]
+features: [Temporal]
+---*/
+
+const actual = [];
+const prototypeDescrs = Object.getOwnPropertyDescriptors(Temporal.ZonedDateTime.prototype);
+const getters = ["year", "month", "monthCode", "day", "hour", "minute", "second", "millisecond", "microsecond", "nanosecond", "calendar"];
+
+for (const property of getters) {
+ Object.defineProperty(Temporal.ZonedDateTime.prototype, property, {
+ get() {
+ actual.push(`get ${property}`);
+ const value = prototypeDescrs[property].get.call(this);
+ return {
+ toString() {
+ actual.push(`toString ${property}`);
+ return value.toString();
+ },
+ valueOf() {
+ actual.push(`valueOf ${property}`);
+ return value;
+ },
+ };
+ },
+ });
+}
+
+const arg = new Temporal.ZonedDateTime(0n, "UTC");
+const instance = new Temporal.Calendar("iso8601");
+instance.monthsInYear(arg);
+assert.compareArray(actual, []);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js
new file mode 100644
index 0000000000..a49579b197
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthsinyear
+description: RangeError thrown if time zone reports an offset that is not an integer number of nanoseconds
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+[3600_000_000_000.5, NaN, -Infinity, Infinity].forEach((wrongOffset) => {
+ const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset);
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ assert.throws(RangeError, () => calendar.monthsInYear(datetime));
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js
new file mode 100644
index 0000000000..aced8bc1b5
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthsinyear
+description: TypeError thrown if timeZone.getOffsetNanosecondsFor is not callable
+features: [BigInt, Symbol, Temporal, arrow-function]
+---*/
+
+[undefined, null, true, Math.PI, 'string', Symbol('sym'), 42n, {}].forEach((notCallable) => {
+ const timeZone = new Temporal.TimeZone("UTC");
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ timeZone.getOffsetNanosecondsFor = notCallable;
+ assert.throws(
+ TypeError,
+ () => calendar.monthsInYear(datetime),
+ `Uncallable ${notCallable === null ? 'null' : typeof notCallable} getOffsetNanosecondsFor should throw TypeError`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js
new file mode 100644
index 0000000000..5a1618fd50
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthsinyear
+description: RangeError thrown if time zone reports an offset that is out of range
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+[-86400_000_000_000, 86400_000_000_000].forEach((wrongOffset) => {
+ const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset);
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ assert.throws(RangeError, () => calendar.monthsInYear(datetime));
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js
new file mode 100644
index 0000000000..794fa1edd6
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthsinyear
+description: TypeError thrown if time zone reports an offset that is not a Number
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+[
+ undefined,
+ null,
+ true,
+ "+01:00",
+ Symbol(),
+ 3600_000_000_000n,
+ {},
+ { valueOf() { return 3600_000_000_000; } },
+].forEach((wrongOffset) => {
+ const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset);
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ assert.throws(TypeError, () => calendar.monthsInYear(datetime));
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/basic.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/basic.js
new file mode 100644
index 0000000000..a74818422a
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/basic.js
@@ -0,0 +1,20 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthsinyear
+description: Basic tests for monthsInYear().
+features: [Temporal]
+---*/
+
+const iso = Temporal.Calendar.from("iso8601");
+const res = 12;
+assert.sameValue(iso.monthsInYear(new Temporal.PlainDate(1994, 11, 5)), res, "PlainDate");
+assert.sameValue(iso.monthsInYear(new Temporal.PlainDateTime(1994, 11, 5, 8, 15, 30)), res, "PlainDateTime");
+assert.sameValue(iso.monthsInYear(new Temporal.PlainYearMonth(1994, 11)), res, "PlainYearMonth");
+assert.sameValue(iso.monthsInYear({ year: 1994, month: 11, day: 5 }), res, "property bag");
+assert.sameValue(iso.monthsInYear("1994-11-05"), res, "string");
+assert.throws(TypeError, () => iso.monthsInYear({ year: 2000 }), "property bag with missing properties");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/branding.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/branding.js
new file mode 100644
index 0000000000..f0733876d6
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/branding.js
@@ -0,0 +1,27 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthsinyear
+description: Throw a TypeError if the receiver is invalid
+features: [Symbol, Temporal]
+---*/
+
+const monthsInYear = Temporal.Calendar.prototype.monthsInYear;
+
+assert.sameValue(typeof monthsInYear, "function");
+
+const args = [new Temporal.PlainDate(2021, 3, 4)];
+
+assert.throws(TypeError, () => monthsInYear.apply(undefined, args), "undefined");
+assert.throws(TypeError, () => monthsInYear.apply(null, args), "null");
+assert.throws(TypeError, () => monthsInYear.apply(true, args), "true");
+assert.throws(TypeError, () => monthsInYear.apply("", args), "empty string");
+assert.throws(TypeError, () => monthsInYear.apply(Symbol(), args), "symbol");
+assert.throws(TypeError, () => monthsInYear.apply(1, args), "1");
+assert.throws(TypeError, () => monthsInYear.apply({}, args), "plain object");
+assert.throws(TypeError, () => monthsInYear.apply(Temporal.Calendar, args), "Temporal.Calendar");
+assert.throws(TypeError, () => monthsInYear.apply(Temporal.Calendar.prototype, args), "Temporal.Calendar.prototype");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/browser.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/browser.js
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/builtin.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/builtin.js
new file mode 100644
index 0000000000..66ec0ebe99
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/builtin.js
@@ -0,0 +1,36 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthsinyear
+description: >
+ Tests that Temporal.Calendar.prototype.monthsInYear
+ meets the requirements for built-in objects defined by the
+ introduction of chapter 17 of the ECMAScript Language Specification.
+info: |
+ Built-in functions that are not constructors do not have a "prototype" property unless
+ otherwise specified in the description of a particular function.
+
+ Unless specified otherwise, a built-in object that is callable as a function is a built-in
+ function object with the characteristics described in 10.3. Unless specified otherwise, the
+ [[Extensible]] internal slot of a built-in object initially has the value true.
+
+ Unless otherwise specified every built-in function and every built-in constructor has the
+ Function prototype object [...] as the value of its [[Prototype]] internal slot.
+features: [Temporal]
+---*/
+
+assert.sameValue(Object.isExtensible(Temporal.Calendar.prototype.monthsInYear),
+ true, "Built-in objects must be extensible.");
+
+assert.sameValue(Object.prototype.toString.call(Temporal.Calendar.prototype.monthsInYear),
+ "[object Function]", "Object.prototype.toString");
+
+assert.sameValue(Object.getPrototypeOf(Temporal.Calendar.prototype.monthsInYear),
+ Function.prototype, "prototype");
+
+assert.sameValue(Temporal.Calendar.prototype.monthsInYear.hasOwnProperty("prototype"),
+ false, "prototype property");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/calendar-datefromfields-called-with-options-undefined.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/calendar-datefromfields-called-with-options-undefined.js
new file mode 100644
index 0000000000..416cc559a1
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/calendar-datefromfields-called-with-options-undefined.js
@@ -0,0 +1,18 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthsinyear
+description: >
+ Calendar.dateFromFields method is called with undefined as the options value
+ when call originates internally
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions();
+calendar.monthsInYear({ year: 2000, month: 5, day: 3, calendar });
+assert.sameValue(calendar.dateFromFieldsCallCount, 1);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/calendar-fields-iterable.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/calendar-fields-iterable.js
new file mode 100644
index 0000000000..80daa1bc7b
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/calendar-fields-iterable.js
@@ -0,0 +1,35 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthsinyear
+description: Verify the result of calendar.fields() is treated correctly.
+info: |
+ sec-temporal.calendar.prototype.monthsinyear step 4:
+ 4. Perform ? ToTemporalDate(_dateOrDateTime_).
+ sec-temporal-totemporaldate step 2.c:
+ c. Let _fieldNames_ be ? CalendarFields(_calendar_, « *"day"*, *"month"*, *"monthCode"*, *"year"* »).
+ sec-temporal-calendarfields step 4:
+ 4. Let _result_ be ? IterableToListOfType(_fieldsArray_, « String »).
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const expected = [
+ "day",
+ "month",
+ "monthCode",
+ "year",
+];
+
+const calendar1 = TemporalHelpers.calendarFieldsIterable();
+const calendar2 = TemporalHelpers.calendarFieldsIterable();
+calendar1.monthsInYear({ year: 2000, month: 5, day: 2, calendar: calendar2 });
+
+assert.sameValue(calendar1.fieldsCallCount, 0, "fields() method not called");
+assert.sameValue(calendar2.fieldsCallCount, 1, "fields() method called once");
+assert.compareArray(calendar2.fieldsCalledWith[0], expected, "fields() method called with correct args");
+assert(calendar2.iteratorExhausted[0], "iterated through the whole iterable");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/calendar-temporal-object.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/calendar-temporal-object.js
new file mode 100644
index 0000000000..b65eff793b
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/calendar-temporal-object.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthsinyear
+description: Fast path for converting other Temporal objects to Temporal.Calendar by reading internal slots
+info: |
+ sec-temporal.calendar.prototype.monthsinyear step 4:
+ 4. Perform ? ToTemporalDate(_dateOrDateTime_).
+ sec-temporal-totemporaldate step 2.c:
+ c. Let _calendar_ be ? GetTemporalCalendarWithISODefault(_item_).
+ sec-temporal-gettemporalcalendarwithisodefault step 2:
+ 2. Return ? ToTemporalCalendarWithISODefault(_calendar_).
+ sec-temporal-totemporalcalendarwithisodefault step 2:
+ 3. Return ? ToTemporalCalendar(_temporalCalendarLike_).
+ sec-temporal-totemporalcalendar step 1.a:
+ a. If _temporalCalendarLike_ has an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]], [[InitializedTemporalMonthDay]], [[InitializedTemporalYearMonth]], or [[InitializedTemporalZonedDateTime]] internal slot, then
+ i. Return _temporalCalendarLike_.[[Calendar]].
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+TemporalHelpers.checkToTemporalCalendarFastPath((temporalObject) => {
+ const calendar = new Temporal.Calendar("iso8601");
+ calendar.monthsInYear({ year: 2000, month: 5, day: 2, calendar: temporalObject });
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/infinity-throws-rangeerror.js
new file mode 100644
index 0000000000..d0937c3663
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/infinity-throws-rangeerror.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: Throws if any value in the property bag is Infinity or -Infinity
+esid: sec-temporal.calendar.prototype.monthsinyear
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+const base = { year: 2000, month: 5, day: 2 };
+
+[Infinity, -Infinity].forEach((inf) => {
+ ["year", "month", "day"].forEach((prop) => {
+ assert.throws(RangeError, () => instance.monthsInYear({ ...base, [prop]: inf }), `${prop} property cannot be ${inf}`);
+
+ const calls = [];
+ const obj = TemporalHelpers.toPrimitiveObserver(calls, inf, prop);
+ assert.throws(RangeError, () => instance.monthsInYear({ ...base, [prop]: obj }));
+ assert.compareArray(calls, [`get ${prop}.valueOf`, `call ${prop}.valueOf`], "it fails after fetching the primitive value");
+ });
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/length.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/length.js
new file mode 100644
index 0000000000..14d9d9d9e1
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/length.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2020 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthsinyear
+description: Temporal.Calendar.prototype.monthsInYear.length is 1
+info: |
+ Every built-in function object, including constructors, has a "length" property whose value is
+ an integer. Unless otherwise specified, this value is equal to the largest number of named
+ arguments shown in the subclause headings for the function description. Optional parameters
+ (which are indicated with brackets: [ ]) or rest parameters (which are shown using the form
+ «...name») are not included in the default argument count.
+
+ Unless otherwise specified, the "length" property of a built-in function object has the
+ attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+verifyProperty(Temporal.Calendar.prototype.monthsInYear, "length", {
+ value: 1,
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/name.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/name.js
new file mode 100644
index 0000000000..bb140c095e
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/name.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthsinyear
+description: Temporal.Calendar.prototype.monthsInYear.name is "monthsInYear".
+info: |
+ Every built-in function object, including constructors, that is not identified as an anonymous
+ function has a "name" property whose value is a String. Unless otherwise specified, this value
+ is the name that is given to the function in this specification.
+
+ Unless otherwise specified, the "name" property of a built-in function object, if it exists,
+ has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+verifyProperty(Temporal.Calendar.prototype.monthsInYear, "name", {
+ value: "monthsInYear",
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/not-a-constructor.js
new file mode 100644
index 0000000000..bf5940e1df
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/not-a-constructor.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthsinyear
+description: >
+ Temporal.Calendar.prototype.monthsInYear does not implement [[Construct]], is not new-able
+info: |
+ Built-in function objects that are not identified as constructors do not implement the
+ [[Construct]] internal method unless otherwise specified in the description of a particular
+ function.
+includes: [isConstructor.js]
+features: [Reflect.construct, Temporal]
+---*/
+
+assert.throws(TypeError, () => {
+ new Temporal.Calendar.prototype.monthsInYear();
+}, "Calling as constructor");
+
+assert.sameValue(isConstructor(Temporal.Calendar.prototype.monthsInYear), false,
+ "isConstructor(Temporal.Calendar.prototype.monthsInYear)");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/prop-desc.js
new file mode 100644
index 0000000000..b6e58dea1e
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/prop-desc.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthsinyear
+description: The "monthsInYear" property of Temporal.Calendar.prototype
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+assert.sameValue(
+ typeof Temporal.Calendar.prototype.monthsInYear,
+ "function",
+ "`typeof Calendar.prototype.monthsInYear` is `function`"
+);
+
+verifyProperty(Temporal.Calendar.prototype, "monthsInYear", {
+ writable: true,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/shell.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/shell.js
new file mode 100644
index 0000000000..eda1477282
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/shell.js
@@ -0,0 +1,24 @@
+// GENERATED, DO NOT EDIT
+// file: isConstructor.js
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: |
+ Test if a given function is a constructor function.
+defines: [isConstructor]
+features: [Reflect.construct]
+---*/
+
+function isConstructor(f) {
+ if (typeof f !== "function") {
+ throw new Test262Error("isConstructor invoked with a non-function value");
+ }
+
+ try {
+ Reflect.construct(function(){}, [], f);
+ } catch (e) {
+ return false;
+ }
+ return true;
+}
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/year-zero.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/year-zero.js
new file mode 100644
index 0000000000..bb6d5c9da8
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/monthsInYear/year-zero.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.monthsinyear
+description: Negative zero, as an extended year, is rejected
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ "-000000-10-31",
+ "-000000-10-31T00:45",
+ "-000000-10-31T00:45+01:00",
+ "-000000-10-31T00:45+00:00[UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.monthsInYear(arg),
+ "reject minus zero as extended year"
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/prop-desc.js
new file mode 100644
index 0000000000..04b8e87d06
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/prop-desc.js
@@ -0,0 +1,21 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal-calendar-prototype
+description: The "prototype" property of Temporal.Calendar
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+assert.sameValue(typeof Temporal.Calendar.prototype, "object");
+assert.notSameValue(Temporal.Calendar.prototype, null);
+
+verifyProperty(Temporal.Calendar, "prototype", {
+ writable: false,
+ enumerable: false,
+ configurable: false,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/shell.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/shell.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/shell.js
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toJSON/branding.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toJSON/branding.js
new file mode 100644
index 0000000000..3c0caacf81
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toJSON/branding.js
@@ -0,0 +1,25 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.tojson
+description: Throw a TypeError if the receiver is invalid
+features: [Symbol, Temporal]
+---*/
+
+const toJSON = Temporal.Calendar.prototype.toJSON;
+
+assert.sameValue(typeof toJSON, "function");
+
+assert.throws(TypeError, () => toJSON.call(undefined), "undefined");
+assert.throws(TypeError, () => toJSON.call(null), "null");
+assert.throws(TypeError, () => toJSON.call(true), "true");
+assert.throws(TypeError, () => toJSON.call(""), "empty string");
+assert.throws(TypeError, () => toJSON.call(Symbol()), "symbol");
+assert.throws(TypeError, () => toJSON.call(1), "1");
+assert.throws(TypeError, () => toJSON.call({}), "plain object");
+assert.throws(TypeError, () => toJSON.call(Temporal.Calendar), "Temporal.Calendar");
+assert.throws(TypeError, () => toJSON.call(Temporal.Calendar.prototype), "Temporal.Calendar.prototype");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toJSON/browser.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toJSON/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toJSON/browser.js
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toJSON/builtin.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toJSON/builtin.js
new file mode 100644
index 0000000000..21a148167a
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toJSON/builtin.js
@@ -0,0 +1,36 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.tojson
+description: >
+ Tests that Temporal.Calendar.prototype.toJSON
+ meets the requirements for built-in objects defined by the
+ introduction of chapter 17 of the ECMAScript Language Specification.
+info: |
+ Built-in functions that are not constructors do not have a "prototype" property unless
+ otherwise specified in the description of a particular function.
+
+ Unless specified otherwise, a built-in object that is callable as a function is a built-in
+ function object with the characteristics described in 10.3. Unless specified otherwise, the
+ [[Extensible]] internal slot of a built-in object initially has the value true.
+
+ Unless otherwise specified every built-in function and every built-in constructor has the
+ Function prototype object [...] as the value of its [[Prototype]] internal slot.
+features: [Temporal]
+---*/
+
+assert.sameValue(Object.isExtensible(Temporal.Calendar.prototype.toJSON),
+ true, "Built-in objects must be extensible.");
+
+assert.sameValue(Object.prototype.toString.call(Temporal.Calendar.prototype.toJSON),
+ "[object Function]", "Object.prototype.toString");
+
+assert.sameValue(Object.getPrototypeOf(Temporal.Calendar.prototype.toJSON),
+ Function.prototype, "prototype");
+
+assert.sameValue(Temporal.Calendar.prototype.toJSON.hasOwnProperty("prototype"),
+ false, "prototype property");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toJSON/length.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toJSON/length.js
new file mode 100644
index 0000000000..7328585d32
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toJSON/length.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.tojson
+description: Temporal.Calendar.prototype.toJSON.length is 0
+info: |
+ Every built-in function object, including constructors, has a "length" property whose value is
+ an integer. Unless otherwise specified, this value is equal to the largest number of named
+ arguments shown in the subclause headings for the function description. Optional parameters
+ (which are indicated with brackets: [ ]) or rest parameters (which are shown using the form
+ «...name») are not included in the default argument count.
+
+ Unless otherwise specified, the "length" property of a built-in function object has the
+ attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+verifyProperty(Temporal.Calendar.prototype.toJSON, "length", {
+ value: 0,
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toJSON/name.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toJSON/name.js
new file mode 100644
index 0000000000..15a3bf26bf
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toJSON/name.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.tojson
+description: Temporal.Calendar.prototype.toJSON.name is "toJSON".
+info: |
+ Every built-in function object, including constructors, that is not identified as an anonymous
+ function has a "name" property whose value is a String. Unless otherwise specified, this value
+ is the name that is given to the function in this specification.
+
+ Unless otherwise specified, the "name" property of a built-in function object, if it exists,
+ has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+verifyProperty(Temporal.Calendar.prototype.toJSON, "name", {
+ value: "toJSON",
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toJSON/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toJSON/not-a-constructor.js
new file mode 100644
index 0000000000..fa6dd3872a
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toJSON/not-a-constructor.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.tojson
+description: >
+ Temporal.Calendar.prototype.toJSON does not implement [[Construct]], is not new-able
+info: |
+ Built-in function objects that are not identified as constructors do not implement the
+ [[Construct]] internal method unless otherwise specified in the description of a particular
+ function.
+includes: [isConstructor.js]
+features: [Reflect.construct, Temporal]
+---*/
+
+assert.throws(TypeError, () => {
+ new Temporal.Calendar.prototype.toJSON();
+}, "Calling as constructor");
+
+assert.sameValue(isConstructor(Temporal.Calendar.prototype.toJSON), false,
+ "isConstructor(Temporal.Calendar.prototype.toJSON)");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toJSON/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toJSON/prop-desc.js
new file mode 100644
index 0000000000..8b0e819c89
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toJSON/prop-desc.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.tojson
+description: The "toJSON" property of Temporal.Calendar.prototype
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+assert.sameValue(
+ typeof Temporal.Calendar.prototype.toJSON,
+ "function",
+ "`typeof Calendar.prototype.toJSON` is `function`"
+);
+
+verifyProperty(Temporal.Calendar.prototype, "toJSON", {
+ writable: true,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toJSON/returns-identifier-slot.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toJSON/returns-identifier-slot.js
new file mode 100644
index 0000000000..297b066c40
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toJSON/returns-identifier-slot.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.tojson
+description: toJSON() returns the internal slot value
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const actual = [];
+
+const calendar = new Temporal.Calendar("iso8601");
+TemporalHelpers.observeProperty(actual, calendar, Symbol.toPrimitive, undefined);
+TemporalHelpers.observeProperty(actual, calendar, "id", "bogus");
+TemporalHelpers.observeProperty(actual, calendar, "toString", function () {
+ actual.push("call calendar.toString");
+ return "gregory";
+});
+
+const result = calendar.toJSON();
+assert.sameValue(result, "iso8601", "toJSON gets the internal slot value");
+assert.compareArray(actual, [], "should not invoke any observable operations");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toJSON/shell.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toJSON/shell.js
new file mode 100644
index 0000000000..eda1477282
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toJSON/shell.js
@@ -0,0 +1,24 @@
+// GENERATED, DO NOT EDIT
+// file: isConstructor.js
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: |
+ Test if a given function is a constructor function.
+defines: [isConstructor]
+features: [Reflect.construct]
+---*/
+
+function isConstructor(f) {
+ if (typeof f !== "function") {
+ throw new Test262Error("isConstructor invoked with a non-function value");
+ }
+
+ try {
+ Reflect.construct(function(){}, [], f);
+ } catch (e) {
+ return false;
+ }
+ return true;
+}
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toString/branding.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toString/branding.js
new file mode 100644
index 0000000000..947edcb284
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toString/branding.js
@@ -0,0 +1,25 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.tostring
+description: Throw a TypeError if the receiver is invalid
+features: [Symbol, Temporal]
+---*/
+
+const toString = Temporal.Calendar.prototype.toString;
+
+assert.sameValue(typeof toString, "function");
+
+assert.throws(TypeError, () => toString.call(undefined), "undefined");
+assert.throws(TypeError, () => toString.call(null), "null");
+assert.throws(TypeError, () => toString.call(true), "true");
+assert.throws(TypeError, () => toString.call(""), "empty string");
+assert.throws(TypeError, () => toString.call(Symbol()), "symbol");
+assert.throws(TypeError, () => toString.call(1), "1");
+assert.throws(TypeError, () => toString.call({}), "plain object");
+assert.throws(TypeError, () => toString.call(Temporal.Calendar), "Temporal.Calendar");
+assert.throws(TypeError, () => toString.call(Temporal.Calendar.prototype), "Temporal.Calendar.prototype");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toString/browser.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toString/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toString/browser.js
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toString/builtin.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toString/builtin.js
new file mode 100644
index 0000000000..6f0e53c4d3
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toString/builtin.js
@@ -0,0 +1,36 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.tostring
+description: >
+ Tests that Temporal.Calendar.prototype.toString
+ meets the requirements for built-in objects defined by the
+ introduction of chapter 17 of the ECMAScript Language Specification.
+info: |
+ Built-in functions that are not constructors do not have a "prototype" property unless
+ otherwise specified in the description of a particular function.
+
+ Unless specified otherwise, a built-in object that is callable as a function is a built-in
+ function object with the characteristics described in 10.3. Unless specified otherwise, the
+ [[Extensible]] internal slot of a built-in object initially has the value true.
+
+ Unless otherwise specified every built-in function and every built-in constructor has the
+ Function prototype object [...] as the value of its [[Prototype]] internal slot.
+features: [Temporal]
+---*/
+
+assert.sameValue(Object.isExtensible(Temporal.Calendar.prototype.toString),
+ true, "Built-in objects must be extensible.");
+
+assert.sameValue(Object.prototype.toString.call(Temporal.Calendar.prototype.toString),
+ "[object Function]", "Object.prototype.toString");
+
+assert.sameValue(Object.getPrototypeOf(Temporal.Calendar.prototype.toString),
+ Function.prototype, "prototype");
+
+assert.sameValue(Temporal.Calendar.prototype.toString.hasOwnProperty("prototype"),
+ false, "prototype property");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toString/length.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toString/length.js
new file mode 100644
index 0000000000..00c4b7f57f
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toString/length.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2020 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.tostring
+description: Temporal.Calendar.prototype.toString.length is 0
+info: |
+ Every built-in function object, including constructors, has a "length" property whose value is
+ an integer. Unless otherwise specified, this value is equal to the largest number of named
+ arguments shown in the subclause headings for the function description. Optional parameters
+ (which are indicated with brackets: [ ]) or rest parameters (which are shown using the form
+ «...name») are not included in the default argument count.
+
+ Unless otherwise specified, the "length" property of a built-in function object has the
+ attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+verifyProperty(Temporal.Calendar.prototype.toString, "length", {
+ value: 0,
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toString/name.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toString/name.js
new file mode 100644
index 0000000000..b5268eef32
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toString/name.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.tostring
+description: Temporal.Calendar.prototype.toString.name is "toString".
+info: |
+ Every built-in function object, including constructors, that is not identified as an anonymous
+ function has a "name" property whose value is a String. Unless otherwise specified, this value
+ is the name that is given to the function in this specification.
+
+ Unless otherwise specified, the "name" property of a built-in function object, if it exists,
+ has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+verifyProperty(Temporal.Calendar.prototype.toString, "name", {
+ value: "toString",
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toString/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toString/not-a-constructor.js
new file mode 100644
index 0000000000..03f2a139ec
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toString/not-a-constructor.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.tostring
+description: >
+ Temporal.Calendar.prototype.toString does not implement [[Construct]], is not new-able
+info: |
+ Built-in function objects that are not identified as constructors do not implement the
+ [[Construct]] internal method unless otherwise specified in the description of a particular
+ function.
+includes: [isConstructor.js]
+features: [Reflect.construct, Temporal]
+---*/
+
+assert.throws(TypeError, () => {
+ new Temporal.Calendar.prototype.toString();
+}, "Calling as constructor");
+
+assert.sameValue(isConstructor(Temporal.Calendar.prototype.toString), false,
+ "isConstructor(Temporal.Calendar.prototype.toString)");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toString/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toString/prop-desc.js
new file mode 100644
index 0000000000..d0b3d53e99
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toString/prop-desc.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.tostring
+description: The "toString" property of Temporal.Calendar.prototype
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+assert.sameValue(
+ typeof Temporal.Calendar.prototype.toString,
+ "function",
+ "`typeof Calendar.prototype.toString` is `function`"
+);
+
+verifyProperty(Temporal.Calendar.prototype, "toString", {
+ writable: true,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toString/shell.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toString/shell.js
new file mode 100644
index 0000000000..eda1477282
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toString/shell.js
@@ -0,0 +1,24 @@
+// GENERATED, DO NOT EDIT
+// file: isConstructor.js
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: |
+ Test if a given function is a constructor function.
+defines: [isConstructor]
+features: [Reflect.construct]
+---*/
+
+function isConstructor(f) {
+ if (typeof f !== "function") {
+ throw new Test262Error("isConstructor invoked with a non-function value");
+ }
+
+ try {
+ Reflect.construct(function(){}, [], f);
+ } catch (e) {
+ return false;
+ }
+ return true;
+}
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toStringTag/browser.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toStringTag/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toStringTag/browser.js
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toStringTag/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toStringTag/prop-desc.js
new file mode 100644
index 0000000000..9ef3a23e21
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toStringTag/prop-desc.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype-@@tostringtag
+description: The @@toStringTag property of Temporal.Calendar
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+verifyProperty(Temporal.Calendar.prototype, Symbol.toStringTag, {
+ value: "Temporal.Calendar",
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toStringTag/shell.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toStringTag/shell.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/toStringTag/shell.js
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-builtin-calendar-no-array-iteration.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-builtin-calendar-no-array-iteration.js
new file mode 100644
index 0000000000..fd0e559c7d
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-builtin-calendar-no-array-iteration.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.weekofyear
+description: >
+ Calling the method with a property bag argument with a builtin calendar causes
+ no observable array iteration when getting the calendar fields.
+features: [Temporal]
+---*/
+
+const arrayPrototypeSymbolIteratorOriginal = Array.prototype[Symbol.iterator];
+Array.prototype[Symbol.iterator] = function arrayIterator() {
+ throw new Test262Error("Array should not be iterated");
+}
+
+const instance = new Temporal.Calendar("iso8601");
+const arg = { year: 2000, month: 5, day: 2, calendar: "iso8601" };
+instance.weekOfYear(arg);
+
+Array.prototype[Symbol.iterator] = arrayPrototypeSymbolIteratorOriginal;
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-calendar-datefromfields-called-with-null-prototype-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-calendar-datefromfields-called-with-null-prototype-fields.js
new file mode 100644
index 0000000000..2e3ae9291d
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-calendar-datefromfields-called-with-null-prototype-fields.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.weekofyear
+description: >
+ Calendar.dateFromFields method is called with a null-prototype fields object
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarCheckFieldsPrototypePollution();
+const instance = new Temporal.Calendar("iso8601");
+const arg = { year: 2000, month: 5, day: 2, calendar };
+instance.weekOfYear(arg);
+assert.sameValue(calendar.dateFromFieldsCallCount, 1, "dateFromFields should be called on the property bag's calendar");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-constructor-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-constructor-in-calendar-fields.js
new file mode 100644
index 0000000000..24b26e1281
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-constructor-in-calendar-fields.js
@@ -0,0 +1,17 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.weekofyear
+description: If a calendar's fields() method returns a field named 'constructor', PrepareTemporalFields should throw a RangeError.
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarWithExtraFields(['constructor']);
+const arg = {year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar};
+const instance = new Temporal.Calendar("iso8601");
+
+assert.throws(RangeError, () => instance.weekOfYear(arg));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-duplicate-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-duplicate-calendar-fields.js
new file mode 100644
index 0000000000..cc1de124c3
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-duplicate-calendar-fields.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.weekofyear
+description: If a calendar's fields() method returns duplicate field names, PrepareTemporalFields should throw a RangeError.
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+for (const extra_fields of [['foo', 'foo'], ['day'], ['month'], ['monthCode'], ['year']]) {
+ const calendar = TemporalHelpers.calendarWithExtraFields(extra_fields);
+ const arg = { year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar };
+ const instance = new Temporal.Calendar("iso8601");
+
+ assert.throws(RangeError, () => instance.weekOfYear(arg));
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-leap-second.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-leap-second.js
new file mode 100644
index 0000000000..00140dd078
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-leap-second.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.weekofyear
+description: Leap second is a valid ISO string for PlainDate
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+let arg = "2016-12-31T23:59:60";
+const result1 = instance.weekOfYear(arg);
+assert.sameValue(
+ result1,
+ 52,
+ "leap second is a valid ISO string for PlainDate"
+);
+
+arg = { year: 2016, month: 12, day: 31, hour: 23, minute: 59, second: 60 };
+const result2 = instance.weekOfYear(arg);
+assert.sameValue(
+ result2,
+ 52,
+ "second: 60 is ignored in property bag for PlainDate"
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-number.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-number.js
new file mode 100644
index 0000000000..d631e5fe18
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-number.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.weekofyear
+description: A number cannot be used in place of a Temporal.PlainDate
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const numbers = [
+ 1,
+ 19761118,
+ -19761118,
+ 1234567890,
+];
+
+for (const arg of numbers) {
+ assert.throws(
+ TypeError,
+ () => instance.weekOfYear(arg),
+ 'Numbers cannot be used in place of an ISO string for PlainDate'
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-plaindate.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-plaindate.js
new file mode 100644
index 0000000000..b7fda66665
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-plaindate.js
@@ -0,0 +1,79 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.weekofyear
+description: >
+ Temporal.Calendar.prototype.weekOfYear will take Temporal.PlainDate object
+ and return the week of year of that date.
+info: |
+ 4. Let temporalDate be ? ToTemporalDate(temporalDateLike).
+ 5. Return 𝔽(! ToISOWeekOfYear(temporalDate.[[ISOYear]], temporalDate.[[ISOMonth]], temporalDate.[[ISODay]])).
+features: [Temporal]
+---*/
+
+const cal = new Temporal.Calendar("iso8601");
+
+// The following week numbers are taken from the table "Examples of contemporary
+// dates around New Year's Day" from
+// https://en.wikipedia.org/wiki/ISO_week_date#Relation_with_the_Gregorian_calendar
+
+let d = new Temporal.PlainDate(1977, 1, 1);
+assert.sameValue(cal.weekOfYear(d), 53, "1977-01-01 is in w53");
+
+d = new Temporal.PlainDate(1977, 1, 2);
+assert.sameValue(cal.weekOfYear(d), 53, "1977-01-02 is in w53");
+
+d = new Temporal.PlainDate(1977, 12, 31);
+assert.sameValue(cal.weekOfYear(d), 52, "1977-12-31 is in w52");
+
+d = new Temporal.PlainDate(1978, 1, 1);
+assert.sameValue(cal.weekOfYear(d), 52, "1978-01-01 is in w52");
+
+d = new Temporal.PlainDate(1978, 1, 2);
+assert.sameValue(cal.weekOfYear(d), 1, "1978-01-02 is in w01");
+
+d = new Temporal.PlainDate(1978, 12, 31);
+assert.sameValue(cal.weekOfYear(d), 52, "1978-12-31 is in w52");
+
+d = new Temporal.PlainDate(1979, 1, 1);
+assert.sameValue(cal.weekOfYear(d), 1, "1979-01-01 is in w01");
+
+d = new Temporal.PlainDate(1979, 12, 30);
+assert.sameValue(cal.weekOfYear(d), 52, "1979-12-30 is in w52");
+
+d = new Temporal.PlainDate(1979, 12, 31);
+assert.sameValue(cal.weekOfYear(d), 1, "1979-12-31 is in w01");
+
+d = new Temporal.PlainDate(1980, 1, 1);
+assert.sameValue(cal.weekOfYear(d), 1, "1980-01-01 is in w01");
+
+d = new Temporal.PlainDate(1980, 12, 28);
+assert.sameValue(cal.weekOfYear(d), 52, "1980-12-28 is in w52");
+
+d = new Temporal.PlainDate(1980, 12, 29);
+assert.sameValue(cal.weekOfYear(d), 1, "1980-12-29 is in w01");
+
+d = new Temporal.PlainDate(1980, 12, 30);
+assert.sameValue(cal.weekOfYear(d), 1, "1980-12-30 is in w01");
+
+d = new Temporal.PlainDate(1980, 12, 31);
+assert.sameValue(cal.weekOfYear(d), 1, "1980-12-31 is in w01");
+
+d = new Temporal.PlainDate(1981, 1, 1);
+assert.sameValue(cal.weekOfYear(d), 1, "1981-01-01 is in w01");
+
+d = new Temporal.PlainDate(1981, 12, 31);
+assert.sameValue(cal.weekOfYear(d), 53, "1981-12-31 is in w53");
+
+d = new Temporal.PlainDate(1982, 1, 1);
+assert.sameValue(cal.weekOfYear(d), 53, "1982-01-01 is in w53");
+
+d = new Temporal.PlainDate(1982, 1, 2);
+assert.sameValue(cal.weekOfYear(d), 53, "1982-01-02 is in w53");
+
+d = new Temporal.PlainDate(1982, 1, 3);
+assert.sameValue(cal.weekOfYear(d), 53, "1982-01-03 is in w53");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-plaindatetime.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-plaindatetime.js
new file mode 100644
index 0000000000..b92cd47f7e
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-plaindatetime.js
@@ -0,0 +1,79 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.weekofyear
+description: >
+ Temporal.Calendar.prototype.weekOfYear will take Temporal.PlainDateTime object
+ and return the week of year of that date.
+info: |
+ 4. Let temporalDate be ? ToTemporalDate(temporalDateLike).
+ 5. Return 𝔽(! ToISOWeekOfYear(temporalDate.[[ISOYear]], temporalDate.[[ISOMonth]], temporalDate.[[ISODay]])).
+features: [Temporal]
+---*/
+
+const cal = new Temporal.Calendar("iso8601");
+
+// The following week numbers are taken from the table "Examples of contemporary
+// dates around New Year's Day" from
+// https://en.wikipedia.org/wiki/ISO_week_date#Relation_with_the_Gregorian_calendar
+
+let dt = new Temporal.PlainDateTime(1977, 1, 1, 9, 8);
+assert.sameValue(cal.weekOfYear(dt), 53, "1977-01-01 is in w53");
+
+dt = new Temporal.PlainDateTime(1977, 1, 2, 9, 8);
+assert.sameValue(cal.weekOfYear(dt), 53, "1977-01-02 is in w53");
+
+dt = new Temporal.PlainDateTime(1977, 12, 31, 9, 8);
+assert.sameValue(cal.weekOfYear(dt), 52, "1977-12-31 is in w52");
+
+dt = new Temporal.PlainDateTime(1978, 1, 1, 9, 8);
+assert.sameValue(cal.weekOfYear(dt), 52, "1978-01-01 is in w52");
+
+dt = new Temporal.PlainDateTime(1978, 1, 2, 9, 8);
+assert.sameValue(cal.weekOfYear(dt), 1, "1978-01-02 is in w01");
+
+dt = new Temporal.PlainDateTime(1978, 12, 31, 9, 8);
+assert.sameValue(cal.weekOfYear(dt), 52, "1978-12-31 is in w52");
+
+dt = new Temporal.PlainDateTime(1979, 1, 1, 9, 8);
+assert.sameValue(cal.weekOfYear(dt), 1, "1979-01-01 is in w01");
+
+dt = new Temporal.PlainDateTime(1979, 12, 30, 9, 8);
+assert.sameValue(cal.weekOfYear(dt), 52, "1979-12-30 is in w52");
+
+dt = new Temporal.PlainDateTime(1979, 12, 31, 9, 8);
+assert.sameValue(cal.weekOfYear(dt), 1, "1979-12-31 is in w01");
+
+dt = new Temporal.PlainDateTime(1980, 1, 1, 9, 8);
+assert.sameValue(cal.weekOfYear(dt), 1, "1980-01-01 is in w01");
+
+dt = new Temporal.PlainDateTime(1980, 12, 28, 9, 8);
+assert.sameValue(cal.weekOfYear(dt), 52, "1980-12-28 is in w52");
+
+dt = new Temporal.PlainDateTime(1980, 12, 29, 9, 8);
+assert.sameValue(cal.weekOfYear(dt), 1, "1980-12-29 is in w01");
+
+dt = new Temporal.PlainDateTime(1980, 12, 30, 9, 8);
+assert.sameValue(cal.weekOfYear(dt), 1, "1980-12-30 is in w01");
+
+dt = new Temporal.PlainDateTime(1980, 12, 31, 9, 8);
+assert.sameValue(cal.weekOfYear(dt), 1, "1980-12-31 is in w01");
+
+dt = new Temporal.PlainDateTime(1981, 1, 1, 9, 8);
+assert.sameValue(cal.weekOfYear(dt), 1, "1981-01-01 is in w01");
+
+dt = new Temporal.PlainDateTime(1981, 12, 31, 9, 8);
+assert.sameValue(cal.weekOfYear(dt), 53, "1981-12-31 is in w53");
+
+dt = new Temporal.PlainDateTime(1982, 1, 1, 9, 8);
+assert.sameValue(cal.weekOfYear(dt), 53, "1982-01-01 is in w53");
+
+dt = new Temporal.PlainDateTime(1982, 1, 2, 9, 8);
+assert.sameValue(cal.weekOfYear(dt), 53, "1982-01-02 is in w53");
+
+dt = new Temporal.PlainDateTime(1982, 1, 3, 9, 8);
+assert.sameValue(cal.weekOfYear(dt), 53, "1982-01-03 is in w53");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-propertybag-calendar-case-insensitive.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-propertybag-calendar-case-insensitive.js
new file mode 100644
index 0000000000..5970881125
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-propertybag-calendar-case-insensitive.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.weekofyear
+description: The calendar name is case-insensitive
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const calendar = "IsO8601";
+
+const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+const result = instance.weekOfYear(arg);
+assert.sameValue(result, 47, "Calendar is case-insensitive");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-propertybag-calendar-leap-second.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-propertybag-calendar-leap-second.js
new file mode 100644
index 0000000000..787d8c128e
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-propertybag-calendar-leap-second.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.weekofyear
+description: Leap second is a valid ISO string for a calendar in a property bag
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const calendar = "2016-12-31T23:59:60";
+
+const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+const result = instance.weekOfYear(arg);
+assert.sameValue(
+ result,
+ 47,
+ "leap second is a valid ISO string for calendar"
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-propertybag-calendar-number.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-propertybag-calendar-number.js
new file mode 100644
index 0000000000..cb4c271731
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-propertybag-calendar-number.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.weekofyear
+description: A number as calendar in a property bag is not accepted
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const numbers = [
+ 1,
+ 19970327,
+ -19970327,
+ 1234567890,
+];
+
+for (const calendar of numbers) {
+ const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+ assert.throws(
+ TypeError,
+ () => instance.weekOfYear(arg),
+ "Numbers cannot be used as a calendar"
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-propertybag-calendar-string.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-propertybag-calendar-string.js
new file mode 100644
index 0000000000..ca01bb614b
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-propertybag-calendar-string.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.weekofyear
+description: A calendar ID is valid input for Calendar
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const calendar = "iso8601";
+
+const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+const result = instance.weekOfYear(arg);
+assert.sameValue(result, 47, `Calendar created from string "${calendar}"`);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-propertybag-calendar-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-propertybag-calendar-wrong-type.js
new file mode 100644
index 0000000000..9c70b5e3fc
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-propertybag-calendar-wrong-type.js
@@ -0,0 +1,46 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.weekofyear
+description: >
+ Appropriate error thrown when a calendar property from a property bag cannot
+ be converted to a calendar object or string
+features: [BigInt, Symbol, Temporal]
+---*/
+
+const timeZone = new Temporal.TimeZone("UTC");
+const instance = new Temporal.Calendar("iso8601");
+
+const primitiveTests = [
+ [null, "null"],
+ [true, "boolean"],
+ ["", "empty string"],
+ [1, "number that doesn't convert to a valid ISO string"],
+ [1n, "bigint"],
+];
+
+for (const [calendar, description] of primitiveTests) {
+ const arg = { year: 2019, monthCode: "M11", day: 1, calendar };
+ assert.throws(
+ typeof calendar === 'string' ? RangeError : TypeError,
+ () => instance.weekOfYear(arg),
+ `${description} does not convert to a valid ISO string`
+ );
+}
+
+const typeErrorTests = [
+ [Symbol(), "symbol"],
+ [{}, "plain object that doesn't implement the protocol"],
+ [new Temporal.TimeZone("UTC"), "time zone instance"],
+ [Temporal.Calendar, "Temporal.Calendar, object"],
+ [Temporal.Calendar.prototype, "Temporal.Calendar.prototype, object"], // fails brand check in dateFromFields()
+];
+
+for (const [calendar, description] of typeErrorTests) {
+ const arg = { year: 2019, monthCode: "M11", day: 1, calendar };
+ assert.throws(TypeError, () => instance.weekOfYear(arg), `${description} is not a valid property bag and does not convert to a string`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-propertybag-calendar-year-zero.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-propertybag-calendar-year-zero.js
new file mode 100644
index 0000000000..023b2ca730
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-propertybag-calendar-year-zero.js
@@ -0,0 +1,27 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.weekofyear
+description: Negative zero, as an extended year, is rejected
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ "-000000-10-31",
+ "-000000-10-31T17:45",
+ "-000000-10-31T17:45Z",
+ "-000000-10-31T17:45+01:00",
+ "-000000-10-31T17:45+00:00[UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.weekOfYear(arg),
+ "reject minus zero as extended year"
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-proto-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-proto-in-calendar-fields.js
new file mode 100644
index 0000000000..d0ef9a8fd8
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-proto-in-calendar-fields.js
@@ -0,0 +1,17 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.weekofyear
+description: If a calendar's fields() method returns a field named '__proto__', PrepareTemporalFields should throw a RangeError.
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarWithExtraFields(['__proto__']);
+const arg = {year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar};
+const instance = new Temporal.Calendar("iso8601");
+
+assert.throws(RangeError, () => instance.weekOfYear(arg));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string-calendar-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string-calendar-annotation.js
new file mode 100644
index 0000000000..89d3de01b9
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string-calendar-annotation.js
@@ -0,0 +1,33 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.weekofyear
+description: Various forms of calendar annotation; critical flag has no effect
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02[u-ca=iso8601]", "without time or time zone"],
+ ["2000-05-02[UTC][u-ca=iso8601]", "with time zone and no time"],
+ ["2000-05-02T15:23[u-ca=iso8601]", "without time zone"],
+ ["2000-05-02T15:23[UTC][u-ca=iso8601]", "with time zone"],
+ ["2000-05-02T15:23[!u-ca=iso8601]", "with ! and no time zone"],
+ ["2000-05-02T15:23[UTC][!u-ca=iso8601]", "with ! and time zone"],
+ ["2000-05-02T15:23[u-ca=iso8601][u-ca=discord]", "second annotation ignored"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.weekOfYear(arg);
+
+ assert.sameValue(
+ result,
+ 18,
+ `calendar annotation (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string-critical-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string-critical-unknown-annotation.js
new file mode 100644
index 0000000000..c031c1d9f6
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string-critical-unknown-annotation.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.weekofyear
+description: Unknown annotations with critical flag are rejected
+features: [Temporal]
+---*/
+
+const invalidStrings = [
+ "1970-01-01[!foo=bar]",
+ "1970-01-01T00:00[!foo=bar]",
+ "1970-01-01T00:00[UTC][!foo=bar]",
+ "1970-01-01T00:00[u-ca=iso8601][!foo=bar]",
+ "1970-01-01T00:00[UTC][!foo=bar][u-ca=iso8601]",
+ "1970-01-01T00:00[foo=bar][!_foo-bar0=Dont-Ignore-This-99999999999]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.weekOfYear(arg),
+ `reject unknown annotation with critical flag: ${arg}`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string-date-with-utc-offset.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string-date-with-utc-offset.js
new file mode 100644
index 0000000000..caf708e268
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string-date-with-utc-offset.js
@@ -0,0 +1,48 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.weekofyear
+description: UTC offset not valid with format that does not include a time
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const validStrings = [
+ "2000-05-02T00+00:00",
+ "2000-05-02T00+00:00[UTC]",
+ "2000-05-02T00+00:00[!UTC]",
+ "2000-05-02T00-02:30[America/St_Johns]",
+];
+
+for (const arg of validStrings) {
+ const result = instance.weekOfYear(arg);
+
+ assert.sameValue(
+ result,
+ 18,
+ `"${arg}" is a valid UTC offset with time for PlainDate`
+ );
+}
+
+const invalidStrings = [
+ "2022-09-15Z",
+ "2022-09-15Z[UTC]",
+ "2022-09-15Z[Europe/Vienna]",
+ "2022-09-15+00:00",
+ "2022-09-15+00:00[UTC]",
+ "2022-09-15-02:30",
+ "2022-09-15-02:30[America/St_Johns]",
+];
+
+for (const arg of invalidStrings) {
+ assert.throws(
+ RangeError,
+ () => instance.weekOfYear(arg),
+ `"${arg}" UTC offset without time is not valid for PlainDate`
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string-invalid.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string-invalid.js
new file mode 100644
index 0000000000..9325337841
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string-invalid.js
@@ -0,0 +1,64 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.weekofyear
+description: >
+ RangeError thrown if an invalid ISO string (or syntactically valid ISO string
+ that is not supported) is used as a PlainDate
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ // invalid ISO strings:
+ "",
+ "invalid iso8601",
+ "2020-01-00",
+ "2020-01-32",
+ "2020-02-30",
+ "2021-02-29",
+ "2020-00-01",
+ "2020-13-01",
+ "2020-01-01T",
+ "2020-01-01T25:00:00",
+ "2020-01-01T01:60:00",
+ "2020-01-01T01:60:61",
+ "2020-01-01junk",
+ "2020-01-01T00:00:00junk",
+ "2020-01-01T00:00:00+00:00junk",
+ "2020-01-01T00:00:00+00:00[UTC]junk",
+ "2020-01-01T00:00:00+00:00[UTC][u-ca=iso8601]junk",
+ "02020-01-01",
+ "2020-001-01",
+ "2020-01-001",
+ "2020-01-01T001",
+ "2020-01-01T01:001",
+ "2020-01-01T01:01:001",
+ // valid, but forms not supported in Temporal:
+ "2020-W01-1",
+ "2020-001",
+ "+0002020-01-01",
+ // valid, but this calendar must not exist:
+ "2020-01-01[u-ca=notexist]",
+ // may be valid in other contexts, but insufficient information for PlainDate:
+ "2020-01",
+ "+002020-01",
+ "01-01",
+ "2020-W01",
+ "P1Y",
+ "-P12Y",
+ // valid, but outside the supported range:
+ "-999999-01-01",
+ "+999999-01-01",
+];
+const instance = new Temporal.Calendar("iso8601");
+for (const arg of invalidStrings) {
+ assert.throws(
+ RangeError,
+ () => instance.weekOfYear(arg),
+ `"${arg}" should not be a valid ISO string for a PlainDate`
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string-multiple-calendar.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string-multiple-calendar.js
new file mode 100644
index 0000000000..9cc6e3b820
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string-multiple-calendar.js
@@ -0,0 +1,32 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.weekofyear
+description: >
+ More than one calendar annotation is not syntactical if any have the criical
+ flag
+features: [Temporal]
+---*/
+
+const invalidStrings = [
+ "1970-01-01[u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01[!u-ca=iso8601][u-ca=iso8601]",
+ "1970-01-01[UTC][u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01[u-ca=iso8601][foo=bar][!u-ca=iso8601]",
+ "1970-01-01T00:00[u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01T00:00[!u-ca=iso8601][u-ca=iso8601]",
+ "1970-01-01T00:00[UTC][u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01T00:00[u-ca=iso8601][foo=bar][!u-ca=iso8601]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.weekOfYear(arg),
+ `reject more than one calendar annotation if any critical: ${arg}`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string-multiple-time-zone.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string-multiple-time-zone.js
new file mode 100644
index 0000000000..72ff52c876
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string-multiple-time-zone.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.weekofyear
+description: More than one time zone annotation is not syntactical
+features: [Temporal]
+---*/
+
+const invalidStrings = [
+ "1970-01-01[UTC][UTC]",
+ "1970-01-01T00:00[UTC][UTC]",
+ "1970-01-01T00:00[!UTC][UTC]",
+ "1970-01-01T00:00[UTC][!UTC]",
+ "1970-01-01T00:00[UTC][u-ca=iso8601][UTC]",
+ "1970-01-01T00:00[UTC][foo=bar][UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.weekOfYear(arg),
+ `reject more than one time zone annotation: ${arg}`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string-time-separators.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string-time-separators.js
new file mode 100644
index 0000000000..7a6839eee8
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string-time-separators.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.weekofyear
+description: Time separator in string argument can vary
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02T15:23", "uppercase T"],
+ ["2000-05-02t15:23", "lowercase T"],
+ ["2000-05-02 15:23", "space between date and time"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.weekOfYear(arg);
+
+ assert.sameValue(
+ result,
+ 18,
+ `variant time separators (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string-time-zone-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string-time-zone-annotation.js
new file mode 100644
index 0000000000..86332e48bc
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string-time-zone-annotation.js
@@ -0,0 +1,38 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.weekofyear
+description: Various forms of time zone annotation; critical flag has no effect
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02[Asia/Kolkata]", "named, with no time"],
+ ["2000-05-02[!Europe/Vienna]", "named, with ! and no time"],
+ ["2000-05-02[+00:00]", "numeric, with no time"],
+ ["2000-05-02[!-02:30]", "numeric, with ! and no time"],
+ ["2000-05-02T15:23[America/Sao_Paulo]", "named, with no offset"],
+ ["2000-05-02T15:23[!Asia/Tokyo]", "named, with ! and no offset"],
+ ["2000-05-02T15:23[-02:30]", "numeric, with no offset"],
+ ["2000-05-02T15:23[!+00:00]", "numeric, with ! and no offset"],
+ ["2000-05-02T15:23+00:00[America/New_York]", "named, with offset"],
+ ["2000-05-02T15:23+00:00[!UTC]", "named, with offset and !"],
+ ["2000-05-02T15:23+00:00[+01:00]", "numeric, with offset"],
+ ["2000-05-02T15:23+00:00[!-08:00]", "numeric, with offset and !"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.weekOfYear(arg);
+
+ assert.sameValue(
+ result,
+ 18,
+ `time zone annotation (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string-unknown-annotation.js
new file mode 100644
index 0000000000..9f91ef3d31
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string-unknown-annotation.js
@@ -0,0 +1,32 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.weekofyear
+description: Various forms of unknown annotation
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02[foo=bar]", "without time"],
+ ["2000-05-02T15:23[foo=bar]", "alone"],
+ ["2000-05-02T15:23[UTC][foo=bar]", "with time zone"],
+ ["2000-05-02T15:23[u-ca=iso8601][foo=bar]", "with calendar"],
+ ["2000-05-02T15:23[UTC][foo=bar][u-ca=iso8601]", "with time zone and calendar"],
+ ["2000-05-02T15:23[foo=bar][_foo-bar0=Ignore-This-999999999999]", "with another unknown annotation"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.weekOfYear(arg);
+
+ assert.sameValue(
+ result,
+ 18,
+ `unknown annotation (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string-with-utc-designator.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string-with-utc-designator.js
new file mode 100644
index 0000000000..f7fc0c82b7
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string-with-utc-designator.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.weekofyear
+description: RangeError thrown if a string with UTC designator is used as a PlainDate
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ "2019-10-01T09:00:00Z",
+ "2019-10-01T09:00:00Z[UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.weekOfYear(arg),
+ "String with UTC designator should not be valid as a PlainDate"
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string.js
new file mode 100644
index 0000000000..0a7b4b90d8
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string.js
@@ -0,0 +1,42 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.weekofyear
+description: >
+ Temporal.Calendar.prototype.weekOfYear will take an ISO 8601 date string and
+ return the week of year of that date.
+info: |
+ 4. Let temporalDate be ? ToTemporalDate(temporalDateLike).
+ 5. Return 𝔽(! ToISOWeekOfYear(temporalDate.[[ISOYear]], temporalDate.[[ISOMonth]], temporalDate.[[ISODay]])).
+features: [Temporal]
+---*/
+
+const cal = new Temporal.Calendar("iso8601");
+
+// The following week numbers are taken from the table "Examples of contemporary
+// dates around New Year's Day" from
+// https://en.wikipedia.org/wiki/ISO_week_date#Relation_with_the_Gregorian_calendar
+
+assert.sameValue(cal.weekOfYear("1977-01-01"), 53, "1977-01-01 is in w53");
+assert.sameValue(cal.weekOfYear("1977-01-02"), 53, "1977-01-02 is in w53");
+assert.sameValue(cal.weekOfYear("1977-12-31"), 52, "1977-12-31 is in w52");
+assert.sameValue(cal.weekOfYear("1978-01-01"), 52, "1978-01-01 is in w52");
+assert.sameValue(cal.weekOfYear("1978-01-02"), 1, "1978-01-02 is in w01");
+assert.sameValue(cal.weekOfYear("1978-12-31"), 52, "1978-12-31 is in w52");
+assert.sameValue(cal.weekOfYear("1979-01-01"), 1, "1979-01-01 is in w01");
+assert.sameValue(cal.weekOfYear("1979-12-30"), 52, "1979-12-30 is in w52");
+assert.sameValue(cal.weekOfYear("1979-12-31"), 1, "1979-12-31 is in w01");
+assert.sameValue(cal.weekOfYear("1980-01-01"), 1, "1980-01-01 is in w01");
+assert.sameValue(cal.weekOfYear("1980-12-28"), 52, "1980-12-28 is in w52");
+assert.sameValue(cal.weekOfYear("1980-12-29"), 1, "1980-12-29 is in w01");
+assert.sameValue(cal.weekOfYear("1980-12-30"), 1, "1980-12-30 is in w01");
+assert.sameValue(cal.weekOfYear("1980-12-31"), 1, "1980-12-31 is in w01");
+assert.sameValue(cal.weekOfYear("1981-01-01"), 1, "1981-01-01 is in w01");
+assert.sameValue(cal.weekOfYear("1981-12-31"), 53, "1981-12-31 is in w53");
+assert.sameValue(cal.weekOfYear("1982-01-01"), 53, "1982-01-01 is in w53");
+assert.sameValue(cal.weekOfYear("1982-01-02"), 53, "1982-01-02 is in w53");
+assert.sameValue(cal.weekOfYear("1982-01-03"), 53, "1982-01-03 is in w53");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-wrong-type.js
new file mode 100644
index 0000000000..85aedab4fa
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-wrong-type.js
@@ -0,0 +1,43 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.weekofyear
+description: >
+ Appropriate error thrown when argument cannot be converted to a valid string
+ or property bag for PlainDate
+features: [BigInt, Symbol, Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const primitiveTests = [
+ [undefined, "undefined"],
+ [null, "null"],
+ [true, "boolean"],
+ ["", "empty string"],
+ [1, "number that doesn't convert to a valid ISO string"],
+ [1n, "bigint"],
+];
+
+for (const [arg, description] of primitiveTests) {
+ assert.throws(
+ typeof arg === 'string' ? RangeError : TypeError,
+ () => instance.weekOfYear(arg),
+ `${description} does not convert to a valid ISO string`
+ );
+}
+
+const typeErrorTests = [
+ [Symbol(), "symbol"],
+ [{}, "plain object"],
+ [Temporal.PlainDate, "Temporal.PlainDate, object"],
+ [Temporal.PlainDate.prototype, "Temporal.PlainDate.prototype, object"],
+];
+
+for (const [arg, description] of typeErrorTests) {
+ assert.throws(TypeError, () => instance.weekOfYear(arg), `${description} is not a valid property bag and does not convert to a string`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-zoneddatetime-convert.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-zoneddatetime-convert.js
new file mode 100644
index 0000000000..60bc7f87ce
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-zoneddatetime-convert.js
@@ -0,0 +1,22 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.weekofyear
+description: An exception from TimeZone#getOffsetNanosecondsFor() is propagated.
+features: [Temporal]
+---*/
+
+class TZ extends Temporal.TimeZone {
+ constructor() { super("UTC") }
+ getOffsetNanosecondsFor() { throw new Test262Error() }
+}
+
+const tz = new TZ();
+const arg = new Temporal.ZonedDateTime(0n, tz);
+const instance = new Temporal.Calendar("iso8601");
+
+assert.throws(Test262Error, () => instance.weekOfYear(arg));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-zoneddatetime-slots.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-zoneddatetime-slots.js
new file mode 100644
index 0000000000..f88b773cf7
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-zoneddatetime-slots.js
@@ -0,0 +1,40 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.weekofyear
+description: Getters are not called when converting a ZonedDateTime to a PlainDate.
+includes: [compareArray.js]
+features: [Temporal]
+---*/
+
+const actual = [];
+const prototypeDescrs = Object.getOwnPropertyDescriptors(Temporal.ZonedDateTime.prototype);
+const getters = ["year", "month", "monthCode", "day", "hour", "minute", "second", "millisecond", "microsecond", "nanosecond", "calendar"];
+
+for (const property of getters) {
+ Object.defineProperty(Temporal.ZonedDateTime.prototype, property, {
+ get() {
+ actual.push(`get ${property}`);
+ const value = prototypeDescrs[property].get.call(this);
+ return {
+ toString() {
+ actual.push(`toString ${property}`);
+ return value.toString();
+ },
+ valueOf() {
+ actual.push(`valueOf ${property}`);
+ return value;
+ },
+ };
+ },
+ });
+}
+
+const arg = new Temporal.ZonedDateTime(0n, "UTC");
+const instance = new Temporal.Calendar("iso8601");
+instance.weekOfYear(arg);
+assert.compareArray(actual, []);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js
new file mode 100644
index 0000000000..5476520dbc
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.weekofyear
+description: RangeError thrown if time zone reports an offset that is not an integer number of nanoseconds
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+[3600_000_000_000.5, NaN, -Infinity, Infinity].forEach((wrongOffset) => {
+ const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset);
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ assert.throws(RangeError, () => calendar.weekOfYear(datetime));
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js
new file mode 100644
index 0000000000..49cfdd2577
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.weekofyear
+description: TypeError thrown if timeZone.getOffsetNanosecondsFor is not callable
+features: [BigInt, Symbol, Temporal, arrow-function]
+---*/
+
+[undefined, null, true, Math.PI, 'string', Symbol('sym'), 42n, {}].forEach((notCallable) => {
+ const timeZone = new Temporal.TimeZone("UTC");
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ timeZone.getOffsetNanosecondsFor = notCallable;
+ assert.throws(
+ TypeError,
+ () => calendar.weekOfYear(datetime),
+ `Uncallable ${notCallable === null ? 'null' : typeof notCallable} getOffsetNanosecondsFor should throw TypeError`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js
new file mode 100644
index 0000000000..546d44e176
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.weekofyear
+description: RangeError thrown if time zone reports an offset that is out of range
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+[-86400_000_000_000, 86400_000_000_000].forEach((wrongOffset) => {
+ const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset);
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ assert.throws(RangeError, () => calendar.weekOfYear(datetime));
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js
new file mode 100644
index 0000000000..72f5d659de
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.weekofyear
+description: TypeError thrown if time zone reports an offset that is not a Number
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+[
+ undefined,
+ null,
+ true,
+ "+01:00",
+ Symbol(),
+ 3600_000_000_000n,
+ {},
+ { valueOf() { return 3600_000_000_000; } },
+].forEach((wrongOffset) => {
+ const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset);
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ assert.throws(TypeError, () => calendar.weekOfYear(datetime));
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/basic.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/basic.js
new file mode 100644
index 0000000000..1eb5ea7100
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/basic.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.weekofyear
+description: Basic tests for weekOfYear().
+features: [Temporal]
+---*/
+
+const iso = Temporal.Calendar.from("iso8601");
+const res = 44;
+assert.sameValue(iso.weekOfYear(Temporal.PlainDate.from("1994-11-05")), res, "PlainDate");
+assert.sameValue(iso.weekOfYear(Temporal.PlainDateTime.from("1994-11-05T08:15:30")), res, "PlainDateTime");
+assert.sameValue(iso.weekOfYear({ year: 1994, month: 11, day: 5 }), res, "property bag");
+assert.sameValue(iso.weekOfYear("1994-11-05"), res, "string");
+assert.throws(TypeError, () => iso.weekOfYear({ year: 2000 }), "property bag with missing properties");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/branding.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/branding.js
new file mode 100644
index 0000000000..ee012dbfa8
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/branding.js
@@ -0,0 +1,27 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.weekofyear
+description: Throw a TypeError if the receiver is invalid
+features: [Symbol, Temporal]
+---*/
+
+const weekOfYear = Temporal.Calendar.prototype.weekOfYear;
+
+assert.sameValue(typeof weekOfYear, "function");
+
+const args = [new Temporal.PlainDate(2021, 7, 20)];
+
+assert.throws(TypeError, () => weekOfYear.apply(undefined, args), "undefined");
+assert.throws(TypeError, () => weekOfYear.apply(null, args), "null");
+assert.throws(TypeError, () => weekOfYear.apply(true, args), "true");
+assert.throws(TypeError, () => weekOfYear.apply("", args), "empty string");
+assert.throws(TypeError, () => weekOfYear.apply(Symbol(), args), "symbol");
+assert.throws(TypeError, () => weekOfYear.apply(1, args), "1");
+assert.throws(TypeError, () => weekOfYear.apply({}, args), "plain object");
+assert.throws(TypeError, () => weekOfYear.apply(Temporal.Calendar, args), "Temporal.Calendar");
+assert.throws(TypeError, () => weekOfYear.apply(Temporal.Calendar.prototype, args), "Temporal.Calendar.prototype");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/browser.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/browser.js
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/builtin.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/builtin.js
new file mode 100644
index 0000000000..9a59d31cc0
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/builtin.js
@@ -0,0 +1,36 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.weekofyear
+description: >
+ Tests that Temporal.Calendar.prototype.weekOfYear
+ meets the requirements for built-in objects defined by the
+ introduction of chapter 17 of the ECMAScript Language Specification.
+info: |
+ Built-in functions that are not constructors do not have a "prototype" property unless
+ otherwise specified in the description of a particular function.
+
+ Unless specified otherwise, a built-in object that is callable as a function is a built-in
+ function object with the characteristics described in 10.3. Unless specified otherwise, the
+ [[Extensible]] internal slot of a built-in object initially has the value true.
+
+ Unless otherwise specified every built-in function and every built-in constructor has the
+ Function prototype object [...] as the value of its [[Prototype]] internal slot.
+features: [Temporal]
+---*/
+
+assert.sameValue(Object.isExtensible(Temporal.Calendar.prototype.weekOfYear),
+ true, "Built-in objects must be extensible.");
+
+assert.sameValue(Object.prototype.toString.call(Temporal.Calendar.prototype.weekOfYear),
+ "[object Function]", "Object.prototype.toString");
+
+assert.sameValue(Object.getPrototypeOf(Temporal.Calendar.prototype.weekOfYear),
+ Function.prototype, "prototype");
+
+assert.sameValue(Temporal.Calendar.prototype.weekOfYear.hasOwnProperty("prototype"),
+ false, "prototype property");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/calendar-datefromfields-called-with-options-undefined.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/calendar-datefromfields-called-with-options-undefined.js
new file mode 100644
index 0000000000..f4259f0eb9
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/calendar-datefromfields-called-with-options-undefined.js
@@ -0,0 +1,18 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.weekofyear
+description: >
+ Calendar.dateFromFields method is called with undefined as the options value
+ when call originates internally
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions();
+calendar.weekOfYear({ year: 2000, month: 5, day: 3, calendar });
+assert.sameValue(calendar.dateFromFieldsCallCount, 1);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/calendar-fields-iterable.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/calendar-fields-iterable.js
new file mode 100644
index 0000000000..b243c771e7
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/calendar-fields-iterable.js
@@ -0,0 +1,35 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.weekofyear
+description: Verify the result of calendar.fields() is treated correctly.
+info: |
+ sec-temporal.calendar.prototype.weekofyear step 4:
+ 4. Let _date_ be ? ToTemporalDate(_dateOrDateTime_).
+ sec-temporal-totemporaldate step 2.c:
+ c. Let _fieldNames_ be ? CalendarFields(_calendar_, « *"day"*, *"month"*, *"monthCode"*, *"year"* »).
+ sec-temporal-calendarfields step 4:
+ 4. Let _result_ be ? IterableToListOfType(_fieldsArray_, « String »).
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const expected = [
+ "day",
+ "month",
+ "monthCode",
+ "year",
+];
+
+const calendar1 = TemporalHelpers.calendarFieldsIterable();
+const calendar2 = TemporalHelpers.calendarFieldsIterable();
+calendar1.weekOfYear({ year: 2000, month: 5, day: 2, calendar: calendar2 });
+
+assert.sameValue(calendar1.fieldsCallCount, 0, "fields() method not called");
+assert.sameValue(calendar2.fieldsCallCount, 1, "fields() method called once");
+assert.compareArray(calendar2.fieldsCalledWith[0], expected, "fields() method called with correct args");
+assert(calendar2.iteratorExhausted[0], "iterated through the whole iterable");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/calendar-temporal-object.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/calendar-temporal-object.js
new file mode 100644
index 0000000000..3f2769d5b3
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/calendar-temporal-object.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.weekofyear
+description: Fast path for converting other Temporal objects to Temporal.Calendar by reading internal slots
+info: |
+ sec-temporal.calendar.prototype.weekofyear step 4:
+ 4. Let _date_ be ? ToTemporalDate(_dateOrDateTime_).
+ sec-temporal-totemporaldate step 2.c:
+ c. Let _calendar_ be ? GetTemporalCalendarWithISODefault(_item_).
+ sec-temporal-gettemporalcalendarwithisodefault step 2:
+ 2. Return ? ToTemporalCalendarWithISODefault(_calendar_).
+ sec-temporal-totemporalcalendarwithisodefault step 2:
+ 3. Return ? ToTemporalCalendar(_temporalCalendarLike_).
+ sec-temporal-totemporalcalendar step 1.a:
+ a. If _temporalCalendarLike_ has an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]], [[InitializedTemporalMonthDay]], [[InitializedTemporalYearMonth]], or [[InitializedTemporalZonedDateTime]] internal slot, then
+ i. Return _temporalCalendarLike_.[[Calendar]].
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+TemporalHelpers.checkToTemporalCalendarFastPath((temporalObject) => {
+ const calendar = new Temporal.Calendar("iso8601");
+ calendar.weekOfYear({ year: 2000, month: 5, day: 2, calendar: temporalObject });
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/cross-year.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/cross-year.js
new file mode 100644
index 0000000000..d65ef91a26
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/cross-year.js
@@ -0,0 +1,15 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.weekofyear
+description: weekOfYear() crossing year boundaries.
+features: [Temporal]
+---*/
+
+const iso = Temporal.Calendar.from("iso8601");
+assert.sameValue(iso.weekOfYear(Temporal.PlainDate.from("2019-12-31")), 1, "week 1 from next year");
+assert.sameValue(iso.weekOfYear(Temporal.PlainDate.from("2021-01-01")), 53, "week 1 from next year");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/infinity-throws-rangeerror.js
new file mode 100644
index 0000000000..f1724eb32d
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/infinity-throws-rangeerror.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: Throws if any value in the property bag is Infinity or -Infinity
+esid: sec-temporal.calendar.prototype.weekofyear
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+const base = { year: 2000, month: 5, day: 2 };
+
+[Infinity, -Infinity].forEach((inf) => {
+ ["year", "month", "day"].forEach((prop) => {
+ assert.throws(RangeError, () => instance.weekOfYear({ ...base, [prop]: inf }), `${prop} property cannot be ${inf}`);
+
+ const calls = [];
+ const obj = TemporalHelpers.toPrimitiveObserver(calls, inf, prop);
+ assert.throws(RangeError, () => instance.weekOfYear({ ...base, [prop]: obj }));
+ assert.compareArray(calls, [`get ${prop}.valueOf`, `call ${prop}.valueOf`], "it fails after fetching the primitive value");
+ });
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/length.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/length.js
new file mode 100644
index 0000000000..97c6fb0a30
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/length.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2020 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.weekofyear
+description: Temporal.Calendar.prototype.weekOfYear.length is 1
+info: |
+ Every built-in function object, including constructors, has a "length" property whose value is
+ an integer. Unless otherwise specified, this value is equal to the largest number of named
+ arguments shown in the subclause headings for the function description. Optional parameters
+ (which are indicated with brackets: [ ]) or rest parameters (which are shown using the form
+ «...name») are not included in the default argument count.
+
+ Unless otherwise specified, the "length" property of a built-in function object has the
+ attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+verifyProperty(Temporal.Calendar.prototype.weekOfYear, "length", {
+ value: 1,
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/name.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/name.js
new file mode 100644
index 0000000000..91d4d267a5
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/name.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.weekofyear
+description: Temporal.Calendar.prototype.weekOfYear.name is "weekOfYear".
+info: |
+ Every built-in function object, including constructors, that is not identified as an anonymous
+ function has a "name" property whose value is a String. Unless otherwise specified, this value
+ is the name that is given to the function in this specification.
+
+ Unless otherwise specified, the "name" property of a built-in function object, if it exists,
+ has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+verifyProperty(Temporal.Calendar.prototype.weekOfYear, "name", {
+ value: "weekOfYear",
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/not-a-constructor.js
new file mode 100644
index 0000000000..21889a2671
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/not-a-constructor.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.weekofyear
+description: >
+ Temporal.Calendar.prototype.weekOfYear does not implement [[Construct]], is not new-able
+info: |
+ Built-in function objects that are not identified as constructors do not implement the
+ [[Construct]] internal method unless otherwise specified in the description of a particular
+ function.
+includes: [isConstructor.js]
+features: [Reflect.construct, Temporal]
+---*/
+
+assert.throws(TypeError, () => {
+ new Temporal.Calendar.prototype.weekOfYear();
+}, "Calling as constructor");
+
+assert.sameValue(isConstructor(Temporal.Calendar.prototype.weekOfYear), false,
+ "isConstructor(Temporal.Calendar.prototype.weekOfYear)");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/prop-desc.js
new file mode 100644
index 0000000000..31a0f5e4fb
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/prop-desc.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.weekofyear
+description: The "weekOfYear" property of Temporal.Calendar.prototype
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+assert.sameValue(
+ typeof Temporal.Calendar.prototype.weekOfYear,
+ "function",
+ "`typeof Calendar.prototype.weekOfYear` is `function`"
+);
+
+verifyProperty(Temporal.Calendar.prototype, "weekOfYear", {
+ writable: true,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/shell.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/shell.js
new file mode 100644
index 0000000000..eda1477282
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/shell.js
@@ -0,0 +1,24 @@
+// GENERATED, DO NOT EDIT
+// file: isConstructor.js
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: |
+ Test if a given function is a constructor function.
+defines: [isConstructor]
+features: [Reflect.construct]
+---*/
+
+function isConstructor(f) {
+ if (typeof f !== "function") {
+ throw new Test262Error("isConstructor invoked with a non-function value");
+ }
+
+ try {
+ Reflect.construct(function(){}, [], f);
+ } catch (e) {
+ return false;
+ }
+ return true;
+}
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/year-zero.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/year-zero.js
new file mode 100644
index 0000000000..e027bfca5c
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/weekOfYear/year-zero.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.weekofyear
+description: Negative zero, as an extended year, is rejected
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ "-000000-10-31",
+ "-000000-10-31T00:45",
+ "-000000-10-31T00:45+01:00",
+ "-000000-10-31T00:45+00:00[UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.weekOfYear(arg),
+ "reject minus zero as extended year"
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-builtin-calendar-no-array-iteration.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-builtin-calendar-no-array-iteration.js
new file mode 100644
index 0000000000..ca4afbce33
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-builtin-calendar-no-array-iteration.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.year
+description: >
+ Calling the method with a property bag argument with a builtin calendar causes
+ no observable array iteration when getting the calendar fields.
+features: [Temporal]
+---*/
+
+const arrayPrototypeSymbolIteratorOriginal = Array.prototype[Symbol.iterator];
+Array.prototype[Symbol.iterator] = function arrayIterator() {
+ throw new Test262Error("Array should not be iterated");
+}
+
+const instance = new Temporal.Calendar("iso8601");
+const arg = { year: 2000, month: 5, day: 2, calendar: "iso8601" };
+instance.year(arg);
+
+Array.prototype[Symbol.iterator] = arrayPrototypeSymbolIteratorOriginal;
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-calendar-datefromfields-called-with-null-prototype-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-calendar-datefromfields-called-with-null-prototype-fields.js
new file mode 100644
index 0000000000..c5b697a625
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-calendar-datefromfields-called-with-null-prototype-fields.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.year
+description: >
+ Calendar.dateFromFields method is called with a null-prototype fields object
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarCheckFieldsPrototypePollution();
+const instance = new Temporal.Calendar("iso8601");
+const arg = { year: 2000, month: 5, day: 2, calendar };
+instance.year(arg);
+assert.sameValue(calendar.dateFromFieldsCallCount, 1, "dateFromFields should be called on the property bag's calendar");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-constructor-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-constructor-in-calendar-fields.js
new file mode 100644
index 0000000000..cbf629b522
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-constructor-in-calendar-fields.js
@@ -0,0 +1,17 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.year
+description: If a calendar's fields() method returns a field named 'constructor', PrepareTemporalFields should throw a RangeError.
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarWithExtraFields(['constructor']);
+const arg = {year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar};
+const instance = new Temporal.Calendar("iso8601");
+
+assert.throws(RangeError, () => instance.year(arg));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-duplicate-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-duplicate-calendar-fields.js
new file mode 100644
index 0000000000..d9ef764654
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-duplicate-calendar-fields.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.year
+description: If a calendar's fields() method returns duplicate field names, PrepareTemporalFields should throw a RangeError.
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+for (const extra_fields of [['foo', 'foo'], ['day'], ['month'], ['monthCode'], ['year']]) {
+ const calendar = TemporalHelpers.calendarWithExtraFields(extra_fields);
+ const arg = { year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar };
+ const instance = new Temporal.Calendar("iso8601");
+
+ assert.throws(RangeError, () => instance.year(arg));
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-leap-second.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-leap-second.js
new file mode 100644
index 0000000000..ed9d642ec9
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-leap-second.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.year
+description: Leap second is a valid ISO string for PlainDate
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+let arg = "2016-12-31T23:59:60";
+const result1 = instance.year(arg);
+assert.sameValue(
+ result1,
+ 2016,
+ "leap second is a valid ISO string for PlainDate"
+);
+
+arg = { year: 2016, month: 12, day: 31, hour: 23, minute: 59, second: 60 };
+const result2 = instance.year(arg);
+assert.sameValue(
+ result2,
+ 2016,
+ "second: 60 is ignored in property bag for PlainDate"
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-number.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-number.js
new file mode 100644
index 0000000000..109a5ff177
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-number.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.year
+description: A number cannot be used in place of a Temporal.PlainDate
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const numbers = [
+ 1,
+ 19761118,
+ -19761118,
+ 1234567890,
+];
+
+for (const arg of numbers) {
+ assert.throws(
+ TypeError,
+ () => instance.year(arg),
+ 'Numbers cannot be used in place of an ISO string for PlainDate'
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-propertybag-calendar-case-insensitive.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-propertybag-calendar-case-insensitive.js
new file mode 100644
index 0000000000..c0eb531ee1
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-propertybag-calendar-case-insensitive.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.year
+description: The calendar name is case-insensitive
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const calendar = "IsO8601";
+
+const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+const result = instance.year(arg);
+assert.sameValue(result, 1976, "Calendar is case-insensitive");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-propertybag-calendar-leap-second.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-propertybag-calendar-leap-second.js
new file mode 100644
index 0000000000..6079a33b9c
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-propertybag-calendar-leap-second.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.year
+description: Leap second is a valid ISO string for a calendar in a property bag
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const calendar = "2016-12-31T23:59:60";
+
+const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+const result = instance.year(arg);
+assert.sameValue(
+ result,
+ 1976,
+ "leap second is a valid ISO string for calendar"
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-propertybag-calendar-number.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-propertybag-calendar-number.js
new file mode 100644
index 0000000000..7ab6fa7b56
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-propertybag-calendar-number.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.year
+description: A number as calendar in a property bag is not accepted
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const numbers = [
+ 1,
+ 19970327,
+ -19970327,
+ 1234567890,
+];
+
+for (const calendar of numbers) {
+ const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+ assert.throws(
+ TypeError,
+ () => instance.year(arg),
+ "Numbers cannot be used as a calendar"
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-propertybag-calendar-string.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-propertybag-calendar-string.js
new file mode 100644
index 0000000000..ebd1c87cb4
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-propertybag-calendar-string.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.year
+description: A calendar ID is valid input for Calendar
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const calendar = "iso8601";
+
+const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+const result = instance.year(arg);
+assert.sameValue(result, 1976, `Calendar created from string "${calendar}"`);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-propertybag-calendar-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-propertybag-calendar-wrong-type.js
new file mode 100644
index 0000000000..803b29f747
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-propertybag-calendar-wrong-type.js
@@ -0,0 +1,46 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.year
+description: >
+ Appropriate error thrown when a calendar property from a property bag cannot
+ be converted to a calendar object or string
+features: [BigInt, Symbol, Temporal]
+---*/
+
+const timeZone = new Temporal.TimeZone("UTC");
+const instance = new Temporal.Calendar("iso8601");
+
+const primitiveTests = [
+ [null, "null"],
+ [true, "boolean"],
+ ["", "empty string"],
+ [1, "number that doesn't convert to a valid ISO string"],
+ [1n, "bigint"],
+];
+
+for (const [calendar, description] of primitiveTests) {
+ const arg = { year: 2019, monthCode: "M11", day: 1, calendar };
+ assert.throws(
+ typeof calendar === 'string' ? RangeError : TypeError,
+ () => instance.year(arg),
+ `${description} does not convert to a valid ISO string`
+ );
+}
+
+const typeErrorTests = [
+ [Symbol(), "symbol"],
+ [{}, "plain object that doesn't implement the protocol"],
+ [new Temporal.TimeZone("UTC"), "time zone instance"],
+ [Temporal.Calendar, "Temporal.Calendar, object"],
+ [Temporal.Calendar.prototype, "Temporal.Calendar.prototype, object"], // fails brand check in dateFromFields()
+];
+
+for (const [calendar, description] of typeErrorTests) {
+ const arg = { year: 2019, monthCode: "M11", day: 1, calendar };
+ assert.throws(TypeError, () => instance.year(arg), `${description} is not a valid property bag and does not convert to a string`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-propertybag-calendar-year-zero.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-propertybag-calendar-year-zero.js
new file mode 100644
index 0000000000..742326e600
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-propertybag-calendar-year-zero.js
@@ -0,0 +1,27 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.year
+description: Negative zero, as an extended year, is rejected
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ "-000000-10-31",
+ "-000000-10-31T17:45",
+ "-000000-10-31T17:45Z",
+ "-000000-10-31T17:45+01:00",
+ "-000000-10-31T17:45+00:00[UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.year(arg),
+ "reject minus zero as extended year"
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-proto-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-proto-in-calendar-fields.js
new file mode 100644
index 0000000000..9f3120fdcd
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-proto-in-calendar-fields.js
@@ -0,0 +1,17 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.year
+description: If a calendar's fields() method returns a field named '__proto__', PrepareTemporalFields should throw a RangeError.
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarWithExtraFields(['__proto__']);
+const arg = {year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar};
+const instance = new Temporal.Calendar("iso8601");
+
+assert.throws(RangeError, () => instance.year(arg));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-string-calendar-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-string-calendar-annotation.js
new file mode 100644
index 0000000000..b43409dfec
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-string-calendar-annotation.js
@@ -0,0 +1,33 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.year
+description: Various forms of calendar annotation; critical flag has no effect
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02[u-ca=iso8601]", "without time or time zone"],
+ ["2000-05-02[UTC][u-ca=iso8601]", "with time zone and no time"],
+ ["2000-05-02T15:23[u-ca=iso8601]", "without time zone"],
+ ["2000-05-02T15:23[UTC][u-ca=iso8601]", "with time zone"],
+ ["2000-05-02T15:23[!u-ca=iso8601]", "with ! and no time zone"],
+ ["2000-05-02T15:23[UTC][!u-ca=iso8601]", "with ! and time zone"],
+ ["2000-05-02T15:23[u-ca=iso8601][u-ca=discord]", "second annotation ignored"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.year(arg);
+
+ assert.sameValue(
+ result,
+ 2000,
+ `calendar annotation (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-string-critical-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-string-critical-unknown-annotation.js
new file mode 100644
index 0000000000..054e3e1151
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-string-critical-unknown-annotation.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.year
+description: Unknown annotations with critical flag are rejected
+features: [Temporal]
+---*/
+
+const invalidStrings = [
+ "1970-01-01[!foo=bar]",
+ "1970-01-01T00:00[!foo=bar]",
+ "1970-01-01T00:00[UTC][!foo=bar]",
+ "1970-01-01T00:00[u-ca=iso8601][!foo=bar]",
+ "1970-01-01T00:00[UTC][!foo=bar][u-ca=iso8601]",
+ "1970-01-01T00:00[foo=bar][!_foo-bar0=Dont-Ignore-This-99999999999]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.year(arg),
+ `reject unknown annotation with critical flag: ${arg}`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-string-date-with-utc-offset.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-string-date-with-utc-offset.js
new file mode 100644
index 0000000000..a8d1259e03
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-string-date-with-utc-offset.js
@@ -0,0 +1,48 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.year
+description: UTC offset not valid with format that does not include a time
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const validStrings = [
+ "2000-05-02T00+00:00",
+ "2000-05-02T00+00:00[UTC]",
+ "2000-05-02T00+00:00[!UTC]",
+ "2000-05-02T00-02:30[America/St_Johns]",
+];
+
+for (const arg of validStrings) {
+ const result = instance.year(arg);
+
+ assert.sameValue(
+ result,
+ 2000,
+ `"${arg}" is a valid UTC offset with time for PlainDate`
+ );
+}
+
+const invalidStrings = [
+ "2022-09-15Z",
+ "2022-09-15Z[UTC]",
+ "2022-09-15Z[Europe/Vienna]",
+ "2022-09-15+00:00",
+ "2022-09-15+00:00[UTC]",
+ "2022-09-15-02:30",
+ "2022-09-15-02:30[America/St_Johns]",
+];
+
+for (const arg of invalidStrings) {
+ assert.throws(
+ RangeError,
+ () => instance.year(arg),
+ `"${arg}" UTC offset without time is not valid for PlainDate`
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-string-invalid.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-string-invalid.js
new file mode 100644
index 0000000000..625844661f
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-string-invalid.js
@@ -0,0 +1,64 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.year
+description: >
+ RangeError thrown if an invalid ISO string (or syntactically valid ISO string
+ that is not supported) is used as a PlainDate
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ // invalid ISO strings:
+ "",
+ "invalid iso8601",
+ "2020-01-00",
+ "2020-01-32",
+ "2020-02-30",
+ "2021-02-29",
+ "2020-00-01",
+ "2020-13-01",
+ "2020-01-01T",
+ "2020-01-01T25:00:00",
+ "2020-01-01T01:60:00",
+ "2020-01-01T01:60:61",
+ "2020-01-01junk",
+ "2020-01-01T00:00:00junk",
+ "2020-01-01T00:00:00+00:00junk",
+ "2020-01-01T00:00:00+00:00[UTC]junk",
+ "2020-01-01T00:00:00+00:00[UTC][u-ca=iso8601]junk",
+ "02020-01-01",
+ "2020-001-01",
+ "2020-01-001",
+ "2020-01-01T001",
+ "2020-01-01T01:001",
+ "2020-01-01T01:01:001",
+ // valid, but forms not supported in Temporal:
+ "2020-W01-1",
+ "2020-001",
+ "+0002020-01-01",
+ // valid, but this calendar must not exist:
+ "2020-01-01[u-ca=notexist]",
+ // may be valid in other contexts, but insufficient information for PlainDate:
+ "2020-01",
+ "+002020-01",
+ "01-01",
+ "2020-W01",
+ "P1Y",
+ "-P12Y",
+ // valid, but outside the supported range:
+ "-999999-01-01",
+ "+999999-01-01",
+];
+const instance = new Temporal.Calendar("iso8601");
+for (const arg of invalidStrings) {
+ assert.throws(
+ RangeError,
+ () => instance.year(arg),
+ `"${arg}" should not be a valid ISO string for a PlainDate`
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-string-multiple-calendar.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-string-multiple-calendar.js
new file mode 100644
index 0000000000..41f297f57e
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-string-multiple-calendar.js
@@ -0,0 +1,32 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.year
+description: >
+ More than one calendar annotation is not syntactical if any have the criical
+ flag
+features: [Temporal]
+---*/
+
+const invalidStrings = [
+ "1970-01-01[u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01[!u-ca=iso8601][u-ca=iso8601]",
+ "1970-01-01[UTC][u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01[u-ca=iso8601][foo=bar][!u-ca=iso8601]",
+ "1970-01-01T00:00[u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01T00:00[!u-ca=iso8601][u-ca=iso8601]",
+ "1970-01-01T00:00[UTC][u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01T00:00[u-ca=iso8601][foo=bar][!u-ca=iso8601]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.year(arg),
+ `reject more than one calendar annotation if any critical: ${arg}`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-string-multiple-time-zone.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-string-multiple-time-zone.js
new file mode 100644
index 0000000000..f1f47b87b7
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-string-multiple-time-zone.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.year
+description: More than one time zone annotation is not syntactical
+features: [Temporal]
+---*/
+
+const invalidStrings = [
+ "1970-01-01[UTC][UTC]",
+ "1970-01-01T00:00[UTC][UTC]",
+ "1970-01-01T00:00[!UTC][UTC]",
+ "1970-01-01T00:00[UTC][!UTC]",
+ "1970-01-01T00:00[UTC][u-ca=iso8601][UTC]",
+ "1970-01-01T00:00[UTC][foo=bar][UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.year(arg),
+ `reject more than one time zone annotation: ${arg}`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-string-time-separators.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-string-time-separators.js
new file mode 100644
index 0000000000..ee9b15226c
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-string-time-separators.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.year
+description: Time separator in string argument can vary
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02T15:23", "uppercase T"],
+ ["2000-05-02t15:23", "lowercase T"],
+ ["2000-05-02 15:23", "space between date and time"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.year(arg);
+
+ assert.sameValue(
+ result,
+ 2000,
+ `variant time separators (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-string-time-zone-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-string-time-zone-annotation.js
new file mode 100644
index 0000000000..144b514253
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-string-time-zone-annotation.js
@@ -0,0 +1,38 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.year
+description: Various forms of time zone annotation; critical flag has no effect
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02[Asia/Kolkata]", "named, with no time"],
+ ["2000-05-02[!Europe/Vienna]", "named, with ! and no time"],
+ ["2000-05-02[+00:00]", "numeric, with no time"],
+ ["2000-05-02[!-02:30]", "numeric, with ! and no time"],
+ ["2000-05-02T15:23[America/Sao_Paulo]", "named, with no offset"],
+ ["2000-05-02T15:23[!Asia/Tokyo]", "named, with ! and no offset"],
+ ["2000-05-02T15:23[-02:30]", "numeric, with no offset"],
+ ["2000-05-02T15:23[!+00:00]", "numeric, with ! and no offset"],
+ ["2000-05-02T15:23+00:00[America/New_York]", "named, with offset"],
+ ["2000-05-02T15:23+00:00[!UTC]", "named, with offset and !"],
+ ["2000-05-02T15:23+00:00[+01:00]", "numeric, with offset"],
+ ["2000-05-02T15:23+00:00[!-08:00]", "numeric, with offset and !"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.year(arg);
+
+ assert.sameValue(
+ result,
+ 2000,
+ `time zone annotation (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-string-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-string-unknown-annotation.js
new file mode 100644
index 0000000000..b95e97476c
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-string-unknown-annotation.js
@@ -0,0 +1,32 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.year
+description: Various forms of unknown annotation
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02[foo=bar]", "without time"],
+ ["2000-05-02T15:23[foo=bar]", "alone"],
+ ["2000-05-02T15:23[UTC][foo=bar]", "with time zone"],
+ ["2000-05-02T15:23[u-ca=iso8601][foo=bar]", "with calendar"],
+ ["2000-05-02T15:23[UTC][foo=bar][u-ca=iso8601]", "with time zone and calendar"],
+ ["2000-05-02T15:23[foo=bar][_foo-bar0=Ignore-This-999999999999]", "with another unknown annotation"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.year(arg);
+
+ assert.sameValue(
+ result,
+ 2000,
+ `unknown annotation (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-string-with-utc-designator.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-string-with-utc-designator.js
new file mode 100644
index 0000000000..3f690f9936
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-string-with-utc-designator.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.year
+description: RangeError thrown if a string with UTC designator is used as a PlainDate
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ "2019-10-01T09:00:00Z",
+ "2019-10-01T09:00:00Z[UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.year(arg),
+ "String with UTC designator should not be valid as a PlainDate"
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-wrong-type.js
new file mode 100644
index 0000000000..dbce82cb1f
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-wrong-type.js
@@ -0,0 +1,43 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.year
+description: >
+ Appropriate error thrown when argument cannot be converted to a valid string
+ or property bag for PlainDate
+features: [BigInt, Symbol, Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const primitiveTests = [
+ [undefined, "undefined"],
+ [null, "null"],
+ [true, "boolean"],
+ ["", "empty string"],
+ [1, "number that doesn't convert to a valid ISO string"],
+ [1n, "bigint"],
+];
+
+for (const [arg, description] of primitiveTests) {
+ assert.throws(
+ typeof arg === 'string' ? RangeError : TypeError,
+ () => instance.year(arg),
+ `${description} does not convert to a valid ISO string`
+ );
+}
+
+const typeErrorTests = [
+ [Symbol(), "symbol"],
+ [{}, "plain object"],
+ [Temporal.PlainDate, "Temporal.PlainDate, object"],
+ [Temporal.PlainDate.prototype, "Temporal.PlainDate.prototype, object"],
+];
+
+for (const [arg, description] of typeErrorTests) {
+ assert.throws(TypeError, () => instance.year(arg), `${description} is not a valid property bag and does not convert to a string`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-zoneddatetime-convert.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-zoneddatetime-convert.js
new file mode 100644
index 0000000000..575167a02e
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-zoneddatetime-convert.js
@@ -0,0 +1,22 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.year
+description: An exception from TimeZone#getOffsetNanosecondsFor() is propagated.
+features: [Temporal]
+---*/
+
+class TZ extends Temporal.TimeZone {
+ constructor() { super("UTC") }
+ getOffsetNanosecondsFor() { throw new Test262Error() }
+}
+
+const tz = new TZ();
+const arg = new Temporal.ZonedDateTime(0n, tz);
+const instance = new Temporal.Calendar("iso8601");
+
+assert.throws(Test262Error, () => instance.year(arg));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-zoneddatetime-slots.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-zoneddatetime-slots.js
new file mode 100644
index 0000000000..c3221920bc
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-zoneddatetime-slots.js
@@ -0,0 +1,40 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.year
+description: Getters are not called when converting a ZonedDateTime to a PlainDate.
+includes: [compareArray.js]
+features: [Temporal]
+---*/
+
+const actual = [];
+const prototypeDescrs = Object.getOwnPropertyDescriptors(Temporal.ZonedDateTime.prototype);
+const getters = ["year", "month", "monthCode", "day", "hour", "minute", "second", "millisecond", "microsecond", "nanosecond", "calendar"];
+
+for (const property of getters) {
+ Object.defineProperty(Temporal.ZonedDateTime.prototype, property, {
+ get() {
+ actual.push(`get ${property}`);
+ const value = prototypeDescrs[property].get.call(this);
+ return {
+ toString() {
+ actual.push(`toString ${property}`);
+ return value.toString();
+ },
+ valueOf() {
+ actual.push(`valueOf ${property}`);
+ return value;
+ },
+ };
+ },
+ });
+}
+
+const arg = new Temporal.ZonedDateTime(0n, "UTC");
+const instance = new Temporal.Calendar("iso8601");
+instance.year(arg);
+assert.compareArray(actual, []);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js
new file mode 100644
index 0000000000..71aef5ef62
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.year
+description: RangeError thrown if time zone reports an offset that is not an integer number of nanoseconds
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+[3600_000_000_000.5, NaN, -Infinity, Infinity].forEach((wrongOffset) => {
+ const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset);
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ assert.throws(RangeError, () => calendar.year(datetime));
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js
new file mode 100644
index 0000000000..fd036d070c
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.year
+description: TypeError thrown if timeZone.getOffsetNanosecondsFor is not callable
+features: [BigInt, Symbol, Temporal, arrow-function]
+---*/
+
+[undefined, null, true, Math.PI, 'string', Symbol('sym'), 42n, {}].forEach((notCallable) => {
+ const timeZone = new Temporal.TimeZone("UTC");
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ timeZone.getOffsetNanosecondsFor = notCallable;
+ assert.throws(
+ TypeError,
+ () => calendar.year(datetime),
+ `Uncallable ${notCallable === null ? 'null' : typeof notCallable} getOffsetNanosecondsFor should throw TypeError`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js
new file mode 100644
index 0000000000..5b11ad3a9c
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.year
+description: RangeError thrown if time zone reports an offset that is out of range
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+[-86400_000_000_000, 86400_000_000_000].forEach((wrongOffset) => {
+ const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset);
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ assert.throws(RangeError, () => calendar.year(datetime));
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js
new file mode 100644
index 0000000000..071389f0ed
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.year
+description: TypeError thrown if time zone reports an offset that is not a Number
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+[
+ undefined,
+ null,
+ true,
+ "+01:00",
+ Symbol(),
+ 3600_000_000_000n,
+ {},
+ { valueOf() { return 3600_000_000_000; } },
+].forEach((wrongOffset) => {
+ const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset);
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ assert.throws(TypeError, () => calendar.year(datetime));
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/basic.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/basic.js
new file mode 100644
index 0000000000..65bc6c05c6
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/basic.js
@@ -0,0 +1,20 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.year
+description: Basic tests for year().
+features: [Temporal]
+---*/
+
+const iso = Temporal.Calendar.from("iso8601");
+const res = 1994;
+assert.sameValue(iso.year(Temporal.PlainDate.from("1994-11-05")), res, "PlainDate");
+assert.sameValue(iso.year(Temporal.PlainDateTime.from("1994-11-05T08:15:30")), res, "PlainDateTime");
+assert.sameValue(iso.year(Temporal.PlainYearMonth.from("1994-11")), res, "PlainYearMonth");
+assert.sameValue(iso.year({ year: 1994, month: 11, day: 5 }), res, "property bag");
+assert.sameValue(iso.year("1994-11-05"), res, "string");
+assert.throws(TypeError, () => iso.year({ month: 5 }), "property bag with missing properties");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/branding.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/branding.js
new file mode 100644
index 0000000000..a0d24974fb
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/branding.js
@@ -0,0 +1,27 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.year
+description: Throw a TypeError if the receiver is invalid
+features: [Symbol, Temporal]
+---*/
+
+const year = Temporal.Calendar.prototype.year;
+
+assert.sameValue(typeof year, "function");
+
+const args = [new Temporal.PlainDate(2000, 1, 1)];
+
+assert.throws(TypeError, () => year.apply(undefined, args), "undefined");
+assert.throws(TypeError, () => year.apply(null, args), "null");
+assert.throws(TypeError, () => year.apply(true, args), "true");
+assert.throws(TypeError, () => year.apply("", args), "empty string");
+assert.throws(TypeError, () => year.apply(Symbol(), args), "symbol");
+assert.throws(TypeError, () => year.apply(1, args), "1");
+assert.throws(TypeError, () => year.apply({}, args), "plain object");
+assert.throws(TypeError, () => year.apply(Temporal.Calendar, args), "Temporal.Calendar");
+assert.throws(TypeError, () => year.apply(Temporal.Calendar.prototype, args), "Temporal.Calendar.prototype");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/browser.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/browser.js
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/builtin.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/builtin.js
new file mode 100644
index 0000000000..8f6eda4a10
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/builtin.js
@@ -0,0 +1,36 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.year
+description: >
+ Tests that Temporal.Calendar.prototype.year
+ meets the requirements for built-in objects defined by the
+ introduction of chapter 17 of the ECMAScript Language Specification.
+info: |
+ Built-in functions that are not constructors do not have a "prototype" property unless
+ otherwise specified in the description of a particular function.
+
+ Unless specified otherwise, a built-in object that is callable as a function is a built-in
+ function object with the characteristics described in 10.3. Unless specified otherwise, the
+ [[Extensible]] internal slot of a built-in object initially has the value true.
+
+ Unless otherwise specified every built-in function and every built-in constructor has the
+ Function prototype object [...] as the value of its [[Prototype]] internal slot.
+features: [Temporal]
+---*/
+
+assert.sameValue(Object.isExtensible(Temporal.Calendar.prototype.year),
+ true, "Built-in objects must be extensible.");
+
+assert.sameValue(Object.prototype.toString.call(Temporal.Calendar.prototype.year),
+ "[object Function]", "Object.prototype.toString");
+
+assert.sameValue(Object.getPrototypeOf(Temporal.Calendar.prototype.year),
+ Function.prototype, "prototype");
+
+assert.sameValue(Temporal.Calendar.prototype.year.hasOwnProperty("prototype"),
+ false, "prototype property");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/calendar-datefromfields-called-with-options-undefined.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/calendar-datefromfields-called-with-options-undefined.js
new file mode 100644
index 0000000000..f2b94e2c0c
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/calendar-datefromfields-called-with-options-undefined.js
@@ -0,0 +1,18 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.year
+description: >
+ Calendar.dateFromFields method is called with undefined as the options value
+ when call originates internally
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions();
+calendar.year({ year: 2000, month: 5, day: 3, calendar });
+assert.sameValue(calendar.dateFromFieldsCallCount, 1);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/calendar-fields-iterable.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/calendar-fields-iterable.js
new file mode 100644
index 0000000000..eb5babfc8b
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/calendar-fields-iterable.js
@@ -0,0 +1,37 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.year
+description: Verify the result of calendar.fields() is treated correctly.
+info: |
+ sec-temporal.calendar.prototype.year step 4:
+ 4. Return ? ISOYear(_dateOrDateTime_).
+ sec-temporal-isoyear step 1.a:
+ a. Set _dateOrDateTime_ to ? ToTemporalDate(_dateOrDateTime_).
+ sec-temporal-totemporaldate step 2.c:
+ c. Let _fieldNames_ be ? CalendarFields(_calendar_, « *"day"*, *"month"*, *"monthCode"*, *"year"* »).
+ sec-temporal-calendarfields step 4:
+ 4. Let _result_ be ? IterableToListOfType(_fieldsArray_, « String »).
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const expected = [
+ "day",
+ "month",
+ "monthCode",
+ "year",
+];
+
+const calendar1 = TemporalHelpers.calendarFieldsIterable();
+const calendar2 = TemporalHelpers.calendarFieldsIterable();
+calendar1.year({ year: 2000, month: 5, day: 2, calendar: calendar2 });
+
+assert.sameValue(calendar1.fieldsCallCount, 0, "fields() method not called");
+assert.sameValue(calendar2.fieldsCallCount, 1, "fields() method called once");
+assert.compareArray(calendar2.fieldsCalledWith[0], expected, "fields() method called with correct args");
+assert(calendar2.iteratorExhausted[0], "iterated through the whole iterable");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/calendar-temporal-object.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/calendar-temporal-object.js
new file mode 100644
index 0000000000..6e1edc8bb5
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/calendar-temporal-object.js
@@ -0,0 +1,31 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.dayofweek
+description: Fast path for converting other Temporal objects to Temporal.Calendar by reading internal slots
+info: |
+ sec-temporal.calendar.prototype.year step 4:
+ 4. Return ? ISOYear(_dateOrDateTime_).
+ sec-temporal-isoyear step 1.a:
+ a. Set _dateOrDateTime_ to ? ToTemporalDate(_dateOrDateTime_).
+ sec-temporal-totemporaldate step 2.c:
+ c. Let _calendar_ be ? GetTemporalCalendarWithISODefault(_item_).
+ sec-temporal-gettemporalcalendarwithisodefault step 2:
+ 2. Return ? ToTemporalCalendarWithISODefault(_calendar_).
+ sec-temporal-totemporalcalendarwithisodefault step 2:
+ 3. Return ? ToTemporalCalendar(_temporalCalendarLike_).
+ sec-temporal-totemporalcalendar step 1.a:
+ a. If _temporalCalendarLike_ has an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]], [[InitializedTemporalMonthDay]], [[InitializedTemporalYearMonth]], or [[InitializedTemporalZonedDateTime]] internal slot, then
+ i. Return _temporalCalendarLike_.[[Calendar]].
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+TemporalHelpers.checkToTemporalCalendarFastPath((temporalObject) => {
+ const calendar = new Temporal.Calendar("iso8601");
+ calendar.year({ year: 2000, month: 5, day: 2, calendar: temporalObject });
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/date-time.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/date-time.js
new file mode 100644
index 0000000000..79d01e7c59
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/date-time.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.year
+description: >
+ Temporal.Calendar.prototype.year will take PlainDateTime and return
+ the value of the year.
+info: |
+ 1. Let calendar be the this value.
+ 2. Perform ? RequireInternalSlot(calendar, [[InitializedTemporalCalendar]]).
+ 3. Assert: calendar.[[Identifier]] is "iso8601".
+ 4. If Type(temporalDateLike) is not Object or temporalDateLike does not have an [[InitializedTemporalDate]] or [[InitializedTemporalYearMonth]] internal slot, then
+ a. Set temporalDateLike to ? ToTemporalDate(temporalDateLike).
+ 5. Return ! ISOYear(temporalDateLike).
+features: [Temporal]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+let dateTime = new Temporal.PlainDateTime(1997, 8, 23, 5, 30, 13)
+assert.sameValue(cal.year(dateTime), 1997, 'cal.year(new Temporal.PlainDateTime(1997, 8, 23, 5, 30, 13)) must return 1997');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/date.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/date.js
new file mode 100644
index 0000000000..22a7117552
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/date.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.year
+description: >
+ Temporal.Calendar.prototype.year will take PlainDate and return
+ the value of the year.
+info: |
+ 1. Let calendar be the this value.
+ 2. Perform ? RequireInternalSlot(calendar, [[InitializedTemporalCalendar]]).
+ 3. Assert: calendar.[[Identifier]] is "iso8601".
+ 4. If Type(temporalDateLike) is not Object or temporalDateLike does not have an [[InitializedTemporalDate]] or [[InitializedTemporalYearMonth]] internal slot, then
+ a. Set temporalDateLike to ? ToTemporalDate(temporalDateLike).
+ 5. Return ! ISOYear(temporalDateLike).
+features: [Temporal]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+let date = new Temporal.PlainDate(2021, 7, 15);
+assert.sameValue(cal.year(date), 2021, 'cal.year(new Temporal.PlainDate(2021, 7, 15)) must return 2021');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/infinity-throws-rangeerror.js
new file mode 100644
index 0000000000..e8cfec61d6
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/infinity-throws-rangeerror.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: Throws if any value in the property bag is Infinity or -Infinity
+esid: sec-temporal.calendar.prototype.year
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+const base = { year: 2000, month: 5, day: 2 };
+
+[Infinity, -Infinity].forEach((inf) => {
+ ["year", "month", "day"].forEach((prop) => {
+ assert.throws(RangeError, () => instance.year({ ...base, [prop]: inf }), `${prop} property cannot be ${inf}`);
+
+ const calls = [];
+ const obj = TemporalHelpers.toPrimitiveObserver(calls, inf, prop);
+ assert.throws(RangeError, () => instance.year({ ...base, [prop]: obj }));
+ assert.compareArray(calls, [`get ${prop}.valueOf`, `call ${prop}.valueOf`], "it fails after fetching the primitive value");
+ });
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/length.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/length.js
new file mode 100644
index 0000000000..7e336f251c
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/length.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2020 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.year
+description: Temporal.Calendar.prototype.year.length is 1
+info: |
+ Every built-in function object, including constructors, has a "length" property whose value is
+ an integer. Unless otherwise specified, this value is equal to the largest number of named
+ arguments shown in the subclause headings for the function description. Optional parameters
+ (which are indicated with brackets: [ ]) or rest parameters (which are shown using the form
+ «...name») are not included in the default argument count.
+
+ Unless otherwise specified, the "length" property of a built-in function object has the
+ attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+verifyProperty(Temporal.Calendar.prototype.year, "length", {
+ value: 1,
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/name.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/name.js
new file mode 100644
index 0000000000..a7205e1c1a
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/name.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.year
+description: Temporal.Calendar.prototype.year.name is "year".
+info: |
+ Every built-in function object, including constructors, that is not identified as an anonymous
+ function has a "name" property whose value is a String. Unless otherwise specified, this value
+ is the name that is given to the function in this specification.
+
+ Unless otherwise specified, the "name" property of a built-in function object, if it exists,
+ has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+verifyProperty(Temporal.Calendar.prototype.year, "name", {
+ value: "year",
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/not-a-constructor.js
new file mode 100644
index 0000000000..f1a6e11107
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/not-a-constructor.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.year
+description: >
+ Temporal.Calendar.prototype.year does not implement [[Construct]], is not new-able
+info: |
+ Built-in function objects that are not identified as constructors do not implement the
+ [[Construct]] internal method unless otherwise specified in the description of a particular
+ function.
+includes: [isConstructor.js]
+features: [Reflect.construct, Temporal]
+---*/
+
+assert.throws(TypeError, () => {
+ new Temporal.Calendar.prototype.year();
+}, "Calling as constructor");
+
+assert.sameValue(isConstructor(Temporal.Calendar.prototype.year), false,
+ "isConstructor(Temporal.Calendar.prototype.year)");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/prop-desc.js
new file mode 100644
index 0000000000..d6caba2847
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/prop-desc.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.year
+description: The "year" property of Temporal.Calendar.prototype
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+assert.sameValue(
+ typeof Temporal.Calendar.prototype.year,
+ "function",
+ "`typeof Calendar.prototype.year` is `function`"
+);
+
+verifyProperty(Temporal.Calendar.prototype, "year", {
+ writable: true,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/shell.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/shell.js
new file mode 100644
index 0000000000..eda1477282
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/shell.js
@@ -0,0 +1,24 @@
+// GENERATED, DO NOT EDIT
+// file: isConstructor.js
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: |
+ Test if a given function is a constructor function.
+defines: [isConstructor]
+features: [Reflect.construct]
+---*/
+
+function isConstructor(f) {
+ if (typeof f !== "function") {
+ throw new Test262Error("isConstructor invoked with a non-function value");
+ }
+
+ try {
+ Reflect.construct(function(){}, [], f);
+ } catch (e) {
+ return false;
+ }
+ return true;
+}
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/string.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/string.js
new file mode 100644
index 0000000000..4774f958ca
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/string.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.year
+description: >
+ Temporal.Calendar.prototype.year will take ISO8601 string and return
+ the value of the year.
+info: |
+ 1. Let calendar be the this value.
+ 2. Perform ? RequireInternalSlot(calendar, [[InitializedTemporalCalendar]]).
+ 3. Assert: calendar.[[Identifier]] is "iso8601".
+ 4. If Type(temporalDateLike) is not Object or temporalDateLike does not have an [[InitializedTemporalDate]] or [[InitializedTemporalYearMonth]] internal slot, then
+ a. Set temporalDateLike to ? ToTemporalDate(temporalDateLike).
+ 5. Return ! ISOYear(temporalDateLike).
+features: [Temporal]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+assert.sameValue(cal.year("2019-03-15"), 2019, 'cal.year("2019-03-15") must return 2019');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/throw-range-error-ToTemporalDate.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/throw-range-error-ToTemporalDate.js
new file mode 100644
index 0000000000..fa86c42a0a
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/throw-range-error-ToTemporalDate.js
@@ -0,0 +1,22 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.year
+description: >
+ Temporal.Calendar.prototype.year throws RangeError on
+ ToTemporalDate when temporalDateLike is invalid string.
+info: |
+ 4. If Type(temporalDateLike) is not Object or temporalDateLike
+ does not have an [[InitializedTemporalDate]] or
+ [[InitializedTemporalYearMonth]] internal slot, then
+ a. Set temporalDateLike to ? ToTemporalDate(temporalDateLike).
+features: [Temporal, arrow-function]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+assert.throws(RangeError, () => cal.year("invalid string"),
+ 'cal.year("invalid string") throws a RangeError exception');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/year-month.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/year-month.js
new file mode 100644
index 0000000000..dfa6c299f4
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/year-month.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.year
+description: >
+ Temporal.Calendar.prototype.year will take PlainYearMonth and return
+ the value of the year.
+info: |
+ 1. Let calendar be the this value.
+ 2. Perform ? RequireInternalSlot(calendar, [[InitializedTemporalCalendar]]).
+ 3. Assert: calendar.[[Identifier]] is "iso8601".
+ 4. If Type(temporalDateLike) is not Object or temporalDateLike does not have an [[InitializedTemporalDate]] or [[InitializedTemporalYearMonth]] internal slot, then
+ a. Set temporalDateLike to ? ToTemporalDate(temporalDateLike).
+ 5. Return ! ISOYear(temporalDateLike).
+features: [Temporal]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+let yearMonth = new Temporal.PlainYearMonth(1999, 6);
+assert.sameValue(cal.year(yearMonth), 1999, 'cal.year(new Temporal.PlainYearMonth(1999, 6)) must return 1999');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/year-zero.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/year-zero.js
new file mode 100644
index 0000000000..2185c1b630
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/year/year-zero.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.year
+description: Negative zero, as an extended year, is rejected
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ "-000000-10-31",
+ "-000000-10-31T00:45",
+ "-000000-10-31T00:45+01:00",
+ "-000000-10-31T00:45+00:00[UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.year(arg),
+ "reject minus zero as extended year"
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/basic.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/basic.js
new file mode 100644
index 0000000000..65e6b5888f
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/basic.js
@@ -0,0 +1,43 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearmonthfromfields
+description: Temporal.Calendar.prototype.yearMonthFromFields return correctly with valid data.
+info: |
+ 1. Let calendar be the this value.
+ 2. Perform ? RequireInternalSlot(calendar, [[InitializedTemporalCalendar]]).
+ 3. Assert: calendar.[[Identifier]] is "iso8601".
+ 4. If Type(fields) is not Object, throw a TypeError exception.
+ 5. Set options to ? GetOptionsObject(options).
+ 6. Let result be ? ISOYearMonthFromFields(fields, options).
+ 7. Return ? CreateTemporalYearMonth(result.[[Year]], result.[[Month]], calendar, result.[[ReferenceISODay]]).
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const cal = new Temporal.Calendar("iso8601")
+
+let result = cal.yearMonthFromFields({ year: 2021, month: 7 });
+TemporalHelpers.assertPlainYearMonth(result, 2021, 7, "M07", "year 2021, month 7");
+result = cal.yearMonthFromFields({ year: 2021, month: 12 });
+TemporalHelpers.assertPlainYearMonth(result, 2021, 12, "M12", "year 2021, month 12");
+result = cal.yearMonthFromFields({ year: 2021, monthCode: "M07" });
+TemporalHelpers.assertPlainYearMonth(result, 2021, 7, "M07", "year 2021, monthCode M07");
+result = cal.yearMonthFromFields({ year: 2021, monthCode: "M12" });
+TemporalHelpers.assertPlainYearMonth(result, 2021, 12, "M12", "year 2021, monthCode M12");
+
+["constrain", "reject"].forEach((overflow) => {
+ const opt = { overflow };
+ result = cal.yearMonthFromFields({ year: 2021, month: 7 }, opt);
+ TemporalHelpers.assertPlainYearMonth(result, 2021, 7, "M07", `year 2021, month 7, overflow ${overflow}`);
+ result = cal.yearMonthFromFields({ year: 2021, month: 12 }, opt);
+ TemporalHelpers.assertPlainYearMonth(result, 2021, 12, "M12", `year 2021, month 12, overflow ${overflow}`);
+ result = cal.yearMonthFromFields({ year: 2021, monthCode: "M07" }, opt);
+ TemporalHelpers.assertPlainYearMonth(result, 2021, 7, "M07", `year 2021, monthCode M07, overflow ${overflow}`);
+ result = cal.yearMonthFromFields({ year: 2021, monthCode: "M12" }, opt);
+ TemporalHelpers.assertPlainYearMonth(result, 2021, 12, "M12", `year 2021, monthCode M12, overflow ${overflow}`);
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/branding.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/branding.js
new file mode 100644
index 0000000000..62dd196840
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/branding.js
@@ -0,0 +1,27 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearmonthfromfields
+description: Throw a TypeError if the receiver is invalid
+features: [Symbol, Temporal]
+---*/
+
+const yearMonthFromFields = Temporal.Calendar.prototype.yearMonthFromFields;
+
+assert.sameValue(typeof yearMonthFromFields, "function");
+
+const args = [{ year: 2021, month: 1 }];
+
+assert.throws(TypeError, () => yearMonthFromFields.apply(undefined, args), "undefined");
+assert.throws(TypeError, () => yearMonthFromFields.apply(null, args), "null");
+assert.throws(TypeError, () => yearMonthFromFields.apply(true, args), "true");
+assert.throws(TypeError, () => yearMonthFromFields.apply("", args), "empty string");
+assert.throws(TypeError, () => yearMonthFromFields.apply(Symbol(), args), "symbol");
+assert.throws(TypeError, () => yearMonthFromFields.apply(1, args), "1");
+assert.throws(TypeError, () => yearMonthFromFields.apply({}, args), "plain object");
+assert.throws(TypeError, () => yearMonthFromFields.apply(Temporal.Calendar, args), "Temporal.Calendar");
+assert.throws(TypeError, () => yearMonthFromFields.apply(Temporal.Calendar.prototype, args), "Temporal.Calendar.prototype");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/browser.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/browser.js
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/builtin.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/builtin.js
new file mode 100644
index 0000000000..0de5aad315
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/builtin.js
@@ -0,0 +1,36 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearmonthfromfields
+description: >
+ Tests that Temporal.Calendar.prototype.yearMonthFromFields
+ meets the requirements for built-in objects defined by the
+ introduction of chapter 17 of the ECMAScript Language Specification.
+info: |
+ Built-in functions that are not constructors do not have a "prototype" property unless
+ otherwise specified in the description of a particular function.
+
+ Unless specified otherwise, a built-in object that is callable as a function is a built-in
+ function object with the characteristics described in 10.3. Unless specified otherwise, the
+ [[Extensible]] internal slot of a built-in object initially has the value true.
+
+ Unless otherwise specified every built-in function and every built-in constructor has the
+ Function prototype object [...] as the value of its [[Prototype]] internal slot.
+features: [Temporal]
+---*/
+
+assert.sameValue(Object.isExtensible(Temporal.Calendar.prototype.yearMonthFromFields),
+ true, "Built-in objects must be extensible.");
+
+assert.sameValue(Object.prototype.toString.call(Temporal.Calendar.prototype.yearMonthFromFields),
+ "[object Function]", "Object.prototype.toString");
+
+assert.sameValue(Object.getPrototypeOf(Temporal.Calendar.prototype.yearMonthFromFields),
+ Function.prototype, "prototype");
+
+assert.sameValue(Temporal.Calendar.prototype.yearMonthFromFields.hasOwnProperty("prototype"),
+ false, "prototype property");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/fields-missing-properties.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/fields-missing-properties.js
new file mode 100644
index 0000000000..528ea2998e
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/fields-missing-properties.js
@@ -0,0 +1,25 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearmonthfromfields
+description: Temporal.Calendar.prototype.yearMonthFromFields will throw TypeError with incorrect input data type.
+info: |
+ 1. Let calendar be the this value.
+ 2. Perform ? RequireInternalSlot(calendar, [[InitializedTemporalCalendar]]).
+ 3. Assert: calendar.[[Identifier]] is "iso8601".
+ 4. If Type(fields) is not Object, throw a TypeError exception.
+ 5. Set options to ? GetOptionsObject(options).
+ 6. Let result be ? ISOYearMonthFromFields(fields, options).
+ 7. Return ? CreateTemporalYearMonth(result.[[Year]], result.[[Month]], calendar, result.[[ReferenceISODay]]).
+features: [Temporal]
+---*/
+
+const cal = new Temporal.Calendar("iso8601")
+
+assert.throws(TypeError, () => cal.yearMonthFromFields({}), "at least one correctly spelled property is required");
+assert.throws(TypeError, () => cal.yearMonthFromFields({ month: 1 }), "year is required");
+assert.throws(TypeError, () => cal.yearMonthFromFields({ year: 2021 }), "month or monthCode is required");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/fields-not-object.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/fields-not-object.js
new file mode 100644
index 0000000000..a8af3e6628
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/fields-not-object.js
@@ -0,0 +1,17 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearmonthfromfields
+description: Throw a TypeError if the fields is not an object
+features: [Symbol, Temporal]
+---*/
+
+const tests = [undefined, null, true, false, "string", Symbol("sym"), Math.PI, Infinity, NaN, 42n];
+const iso = Temporal.Calendar.from("iso8601");
+for (const fields of tests) {
+ assert.throws(TypeError, () => iso.yearMonthFromFields(fields, {}));
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/infinity-throws-rangeerror.js
new file mode 100644
index 0000000000..7c7f33f3a9
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/infinity-throws-rangeerror.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: Throws if any value in the property bag is Infinity or -Infinity
+esid: sec-temporal.calendar.prototype.yearmonthfromfields
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+const base = { year: 2000, month: 5 };
+
+[Infinity, -Infinity].forEach((inf) => {
+ ["year", "month"].forEach((prop) => {
+ ["constrain", "reject"].forEach((overflow) => {
+ assert.throws(RangeError, () => instance.yearMonthFromFields({ ...base, [prop]: inf }, { overflow }), `${prop} property cannot be ${inf} (overflow ${overflow}`);
+
+ const calls = [];
+ const obj = TemporalHelpers.toPrimitiveObserver(calls, inf, prop);
+ assert.throws(RangeError, () => instance.yearMonthFromFields({ ...base, [prop]: obj }, { overflow }));
+ assert.compareArray(calls, [`get ${prop}.valueOf`, `call ${prop}.valueOf`], "it fails after fetching the primitive value");
+ });
+ });
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/length.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/length.js
new file mode 100644
index 0000000000..b87ac41bb3
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/length.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2020 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearmonthfromfields
+description: Temporal.Calendar.prototype.yearMonthFromFields.length is 1
+info: |
+ Every built-in function object, including constructors, has a "length" property whose value is
+ an integer. Unless otherwise specified, this value is equal to the largest number of named
+ arguments shown in the subclause headings for the function description. Optional parameters
+ (which are indicated with brackets: [ ]) or rest parameters (which are shown using the form
+ «...name») are not included in the default argument count.
+
+ Unless otherwise specified, the "length" property of a built-in function object has the
+ attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+verifyProperty(Temporal.Calendar.prototype.yearMonthFromFields, "length", {
+ value: 1,
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/missing-properties.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/missing-properties.js
new file mode 100644
index 0000000000..9de556a653
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/missing-properties.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearmonthfromfields
+description: Errors due to missing properties on fields object are thrown in the correct order
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+let getMonth = false;
+let getMonthCode = false;
+const missingYearAndMonth = {
+ get month() {
+ getMonth = true;
+ },
+ get monthCode() {
+ getMonthCode = true;
+ },
+};
+assert.throws(TypeError, () => instance.yearMonthFromFields(missingYearAndMonth), "year should be checked after fetching but before resolving the month");
+assert(getMonth, "year is fetched after month");
+assert(getMonthCode, "year is fetched after monthCode");
+
+assert.throws(TypeError, () => instance.yearMonthFromFields({ year: 2000 }), "month should be resolved last");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/monthcode-invalid.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/monthcode-invalid.js
new file mode 100644
index 0000000000..41ca759058
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/monthcode-invalid.js
@@ -0,0 +1,34 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearmonthfromfields
+description: Throw RangeError for an out-of-range, conflicting, or ill-formed monthCode
+info: |
+ 1. Let calendar be the this value.
+ 2. Perform ? RequireInternalSlot(calendar, [[InitializedTemporalCalendar]]).
+ 3. Assert: calendar.[[Identifier]] is "iso8601".
+ 4. If Type(fields) is not Object, throw a TypeError exception.
+ 5. Set options to ? GetOptionsObject(options).
+ 6. Let result be ? ISOYearMonthFromFields(fields, options).
+ 7. Return ? CreateTemporalYearMonth(result.[[Year]], result.[[Month]], calendar, result.[[ReferenceISODay]]).
+features: [Temporal]
+---*/
+
+const cal = new Temporal.Calendar("iso8601");
+
+["m1", "M1", "m01"].forEach((monthCode) => {
+ assert.throws(RangeError, () => cal.yearMonthFromFields({ year: 2021, monthCode }),
+ `monthCode '${monthCode}' is not well-formed`);
+});
+
+assert.throws(RangeError, () => cal.yearMonthFromFields({ year: 2021, month: 12, monthCode: "M11" }),
+ "monthCode and month conflict");
+
+["M00", "M19", "M99", "M13"].forEach((monthCode) => {
+ assert.throws(RangeError, () => cal.yearMonthFromFields({ year: 2021, monthCode }),
+ `monthCode '${monthCode}' is not valid for year 2021`);
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/name.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/name.js
new file mode 100644
index 0000000000..70c404a728
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/name.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearmonthfromfields
+description: Temporal.Calendar.prototype.yearMonthFromFields.name is "yearMonthFromFields".
+info: |
+ Every built-in function object, including constructors, that is not identified as an anonymous
+ function has a "name" property whose value is a String. Unless otherwise specified, this value
+ is the name that is given to the function in this specification.
+
+ Unless otherwise specified, the "name" property of a built-in function object, if it exists,
+ has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+verifyProperty(Temporal.Calendar.prototype.yearMonthFromFields, "name", {
+ value: "yearMonthFromFields",
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/not-a-constructor.js
new file mode 100644
index 0000000000..58c175cb8b
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/not-a-constructor.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearmonthfromfields
+description: >
+ Temporal.Calendar.prototype.yearMonthFromFields does not implement [[Construct]], is not new-able
+info: |
+ Built-in function objects that are not identified as constructors do not implement the
+ [[Construct]] internal method unless otherwise specified in the description of a particular
+ function.
+includes: [isConstructor.js]
+features: [Reflect.construct, Temporal]
+---*/
+
+assert.throws(TypeError, () => {
+ new Temporal.Calendar.prototype.yearMonthFromFields();
+}, "Calling as constructor");
+
+assert.sameValue(isConstructor(Temporal.Calendar.prototype.yearMonthFromFields), false,
+ "isConstructor(Temporal.Calendar.prototype.yearMonthFromFields)");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/one-of-era-erayear-undefined.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/one-of-era-erayear-undefined.js
new file mode 100644
index 0000000000..6696311237
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/one-of-era-erayear-undefined.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearMonthFromFields
+description: Does not throw a RangeError if only one of era/eraYear fields is present
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+const base = { year: 2000, month: 5, day: 2, era: 'ce' };
+const instance = new Temporal.Calendar('iso8601');
+TemporalHelpers.assertPlainYearMonth(instance.yearMonthFromFields({ ...base }), 2000, 5, 'M05');
+
+const base2 = { year: 2000, month: 5, day: 2, eraYear: 1 };
+TemporalHelpers.assertPlainYearMonth(instance.yearMonthFromFields({ ...base }), 2000, 5, 'M05');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/options-not-object.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/options-not-object.js
new file mode 100644
index 0000000000..65df607e7f
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/options-not-object.js
@@ -0,0 +1,20 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearmonthfromfields
+description: Throw a TypeError if options is not an object or undefined
+info: |
+ 5. Set options to ? GetOptionsObject(options).
+features: [Symbol, Temporal]
+---*/
+
+const tests = [null, true, false, "string", Symbol("sym"), Math.PI, Infinity, NaN, 42n];
+const iso = new Temporal.Calendar("iso8601");
+for (const options of tests) {
+ assert.throws(TypeError, () => iso.yearMonthFromFields({ year: 2021, month: 7 }, options),
+ "options is not object");
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/options-object.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/options-object.js
new file mode 100644
index 0000000000..4fc1e15706
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/options-object.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearmonthfromfields
+description: Empty or a function object may be used as options
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const result1 = instance.yearMonthFromFields({ year: 2000, monthCode: "M05" }, {});
+TemporalHelpers.assertPlainYearMonth(
+ result1, 2000, 5, "M05",
+ "options may be an empty plain object"
+);
+
+const result2 = instance.yearMonthFromFields({ year: 2000, monthCode: "M05" }, () => {});
+TemporalHelpers.assertPlainYearMonth(
+ result2, 2000, 5, "M05",
+ "options may be a function object"
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/options-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/options-wrong-type.js
new file mode 100644
index 0000000000..4c0d750067
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/options-wrong-type.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearmonthfromfields
+description: TypeError thrown when options argument is a primitive
+features: [BigInt, Symbol, Temporal]
+---*/
+
+const badOptions = [
+ null,
+ true,
+ "some string",
+ Symbol(),
+ 1,
+ 2n,
+];
+
+const instance = new Temporal.Calendar("iso8601");
+for (const value of badOptions) {
+ assert.throws(TypeError, () => instance.yearMonthFromFields({ year: 2000, monthCode: "M05" }, value),
+ `TypeError on wrong options type ${typeof value}`);
+};
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/order-of-operations.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/order-of-operations.js
new file mode 100644
index 0000000000..f66a3915a5
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/order-of-operations.js
@@ -0,0 +1,45 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearmonthfromfields
+description: Properties on objects passed to yearMonthFromFields() are accessed in the correct order
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const expected = [
+ "get fields.month",
+ "get fields.month.valueOf",
+ "call fields.month.valueOf",
+ "get fields.monthCode",
+ "get fields.monthCode.toString",
+ "call fields.monthCode.toString",
+ "get fields.year",
+ "get fields.year.valueOf",
+ "call fields.year.valueOf",
+ "get options.overflow",
+ "get options.overflow.toString",
+ "call options.overflow.toString",
+];
+const actual = [];
+
+const instance = new Temporal.Calendar("iso8601");
+
+const fields = TemporalHelpers.propertyBagObserver(actual, {
+ year: 1.7,
+ month: 1.7,
+ monthCode: "M01",
+}, "fields");
+
+const options = TemporalHelpers.propertyBagObserver(actual, {
+ overflow: "reject",
+}, "options");
+
+const result = instance.yearMonthFromFields(fields, options);
+TemporalHelpers.assertPlainYearMonth(result, 1, 1, "M01", "yearMonth result");
+assert.sameValue(result.getISOFields().calendar, "iso8601", "calendar slot should store a string");
+assert.compareArray(actual, expected, "order of operations");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/overflow-constrain.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/overflow-constrain.js
new file mode 100644
index 0000000000..8a7a1b1ee2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/overflow-constrain.js
@@ -0,0 +1,94 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearmonthfromfields
+description: Temporal.Calendar.prototype.yearMonthFromFields will return correctly with data and overflow set to 'constrain'.
+info: |
+ 1. Let calendar be the this value.
+ 2. Perform ? RequireInternalSlot(calendar, [[InitializedTemporalCalendar]]).
+ 3. Assert: calendar.[[Identifier]] is "iso8601".
+ 4. If Type(fields) is not Object, throw a TypeError exception.
+ 5. Set options to ? GetOptionsObject(options).
+ 6. Let result be ? ISOYearMonthFromFields(fields, options).
+ 7. Return ? CreateTemporalYearMonth(result.[[Year]], result.[[Month]], calendar, result.[[ReferenceISODay]]).
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const cal = new Temporal.Calendar("iso8601")
+const opt = { overflow: "constrain" };
+
+let result = cal.yearMonthFromFields({ year: 2021, month: 1 }, opt);
+TemporalHelpers.assertPlainYearMonth(result, 2021, 1, "M01", "month 1 with overflow constrain");
+result = cal.yearMonthFromFields({ year: 2021, month: 2 }, opt);
+TemporalHelpers.assertPlainYearMonth(result, 2021, 2, "M02", "month 2 with overflow constrain");
+result = cal.yearMonthFromFields({ year: 2021, month: 3 }, opt);
+TemporalHelpers.assertPlainYearMonth(result, 2021, 3, "M03", "month 3 with overflow constrain");
+result = cal.yearMonthFromFields({ year: 2021, month: 4 }, opt);
+TemporalHelpers.assertPlainYearMonth(result, 2021, 4, "M04", "month 4 with overflow constrain");
+result = cal.yearMonthFromFields({ year: 2021, month: 5 }, opt);
+TemporalHelpers.assertPlainYearMonth(result, 2021, 5, "M05", "month 5 with overflow constrain");
+result = cal.yearMonthFromFields({ year: 2021, month: 6 }, opt);
+TemporalHelpers.assertPlainYearMonth(result, 2021, 6, "M06", "month 6 with overflow constrain");
+result = cal.yearMonthFromFields({ year: 2021, month: 7 }, opt);
+TemporalHelpers.assertPlainYearMonth(result, 2021, 7, "M07", "month 7 with overflow constrain");
+result = cal.yearMonthFromFields({ year: 2021, month: 8 }, opt);
+TemporalHelpers.assertPlainYearMonth(result, 2021, 8, "M08", "month 8 with overflow constrain");
+result = cal.yearMonthFromFields({ year: 2021, month: 9 }, opt);
+TemporalHelpers.assertPlainYearMonth(result, 2021, 9, "M09", "month 9 with overflow constrain");
+result = cal.yearMonthFromFields({ year: 2021, month: 10 }, opt);
+TemporalHelpers.assertPlainYearMonth(result, 2021, 10, "M10", "month 10 with overflow constrain");
+result = cal.yearMonthFromFields({ year: 2021, month: 11 }, opt);
+TemporalHelpers.assertPlainYearMonth(result, 2021, 11, "M11", "month 11 with overflow constrain");
+result = cal.yearMonthFromFields({ year: 2021, month: 12 }, opt);
+TemporalHelpers.assertPlainYearMonth(result, 2021, 12, "M12", "month 12 with overflow constrain");
+
+assert.throws(
+ RangeError,
+ () => cal.yearMonthFromFields({ year: 2021, month: -99999 }, opt),
+ "negative month -99999 is out of range even with overflow constrain"
+)
+assert.throws(
+ RangeError,
+ () => cal.yearMonthFromFields({ year: 2021, month: -1 }, opt),
+ "negative month -1 is out of range even with overflow constrain"
+)
+assert.throws(
+ RangeError,
+ () => cal.yearMonthFromFields({ year: 2021, month: 0 }, opt),
+ "month zero is out of range even with overflow constrain"
+)
+
+result = cal.yearMonthFromFields({ year: 2021, month: 13 }, opt);
+TemporalHelpers.assertPlainYearMonth(result, 2021, 12, "M12", "month 13 is constrained to 12");
+result = cal.yearMonthFromFields({ year: 2021, month: 99999 }, opt);
+TemporalHelpers.assertPlainYearMonth(result, 2021, 12, "M12", "month 99999 is constrained to 12");
+
+result = cal.yearMonthFromFields({ year: 2021, monthCode: "M01" }, opt);
+TemporalHelpers.assertPlainYearMonth(result, 2021, 1, "M01", "monthCode M01 with overflow constrain");
+result = cal.yearMonthFromFields({ year: 2021, monthCode: "M02" }, opt);
+TemporalHelpers.assertPlainYearMonth(result, 2021, 2, "M02", "monthCode M02 with overflow constrain");
+result = cal.yearMonthFromFields({ year: 2021, monthCode: "M03" }, opt);
+TemporalHelpers.assertPlainYearMonth(result, 2021, 3, "M03", "monthCode M03 with overflow constrain");
+result = cal.yearMonthFromFields({ year: 2021, monthCode: "M04" }, opt);
+TemporalHelpers.assertPlainYearMonth(result, 2021, 4, "M04", "monthCode M04 with overflow constrain");
+result = cal.yearMonthFromFields({ year: 2021, monthCode: "M05" }, opt);
+TemporalHelpers.assertPlainYearMonth(result, 2021, 5, "M05", "monthCode M05 with overflow constrain");
+result = cal.yearMonthFromFields({ year: 2021, monthCode: "M06" }, opt);
+TemporalHelpers.assertPlainYearMonth(result, 2021, 6, "M06", "monthCode M06 with overflow constrain");
+result = cal.yearMonthFromFields({ year: 2021, monthCode: "M07" }, opt);
+TemporalHelpers.assertPlainYearMonth(result, 2021, 7, "M07", "monthCode M07 with overflow constrain");
+result = cal.yearMonthFromFields({ year: 2021, monthCode: "M08" }, opt);
+TemporalHelpers.assertPlainYearMonth(result, 2021, 8, "M08", "monthCode M08 with overflow constrain");
+result = cal.yearMonthFromFields({ year: 2021, monthCode: "M09" }, opt);
+TemporalHelpers.assertPlainYearMonth(result, 2021, 9, "M09", "monthCode M09 with overflow constrain");
+result = cal.yearMonthFromFields({ year: 2021, monthCode: "M10" }, opt);
+TemporalHelpers.assertPlainYearMonth(result, 2021, 10, "M10", "monthCode M10 with overflow constrain");
+result = cal.yearMonthFromFields({ year: 2021, monthCode: "M11" }, opt);
+TemporalHelpers.assertPlainYearMonth(result, 2021, 11, "M11", "monthCode M11 with overflow constrain");
+result = cal.yearMonthFromFields({ year: 2021, monthCode: "M12" }, opt);
+TemporalHelpers.assertPlainYearMonth(result, 2021, 12, "M12", "monthCode M12 with overflow constrain");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/overflow-invalid-string.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/overflow-invalid-string.js
new file mode 100644
index 0000000000..db60f50816
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/overflow-invalid-string.js
@@ -0,0 +1,30 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearmonthfromfields
+description: RangeError thrown when overflow option not one of the allowed string values
+info: |
+ sec-getoption step 10:
+ 10. If _values_ is not *undefined* and _values_ does not contain an element equal to _value_, throw a *RangeError* exception.
+ sec-temporal-totemporaloverflow step 1:
+ 1. Return ? GetOption(_normalizedOptions_, *"overflow"*, « String », « *"constrain"*, *"reject"* », *"constrain"*).
+ sec-temporal-isoyearmonthfromfields step 2:
+ 2. Let _overflow_ be ? ToTemporalOverflow(_options_).
+ sec-temporal.calendar.prototype.yearmonthfromfields step 6:
+ 6. Let _result_ be ? ISOYearMonthFromFields(_fields_, _options_).
+features: [Temporal]
+---*/
+
+const calendar = new Temporal.Calendar("iso8601");
+const badOverflows = ["", "CONSTRAIN", "balance", "other string", "constra\u0131n", "reject\0"];
+for (const overflow of badOverflows) {
+ assert.throws(
+ RangeError,
+ () => calendar.yearMonthFromFields({ year: 2000, month: 5 }, { overflow }),
+ `invalid overflow ("${overflow}")`
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/overflow-reject.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/overflow-reject.js
new file mode 100644
index 0000000000..8c0e3efb27
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/overflow-reject.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearmonthfromfields
+description: Throw RangeError for input data out of range with overflow reject
+info: |
+ 1. Let calendar be the this value.
+ 2. Perform ? RequireInternalSlot(calendar, [[InitializedTemporalCalendar]]).
+ 3. Assert: calendar.[[Identifier]] is "iso8601".
+ 4. If Type(fields) is not Object, throw a TypeError exception.
+ 5. Set options to ? GetOptionsObject(options).
+ 6. Let result be ? ISOYearMonthFromFields(fields, options).
+ 7. Return ? CreateTemporalYearMonth(result.[[Year]], result.[[Month]], calendar, result.[[ReferenceISODay]]).
+features: [Temporal]
+---*/
+
+const cal = new Temporal.Calendar("iso8601");
+
+[-1, 0, 13, 9995].forEach((month) => {
+ assert.throws(
+ RangeError,
+ () => cal.yearMonthFromFields({year: 2021, month, day: 5}, { overflow: "reject" }),
+ `Month ${month} is out of range for 2021 with overflow: reject`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/overflow-undefined.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/overflow-undefined.js
new file mode 100644
index 0000000000..fe8e825846
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/overflow-undefined.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearmonthfromfields
+description: Fallback value for overflow option
+info: |
+ sec-getoption step 3:
+ 3. If _value_ is *undefined*, return _fallback_.
+ sec-temporal-totemporaloverflow step 1:
+ 1. Return ? GetOption(_normalizedOptions_, *"overflow"*, « String », « *"constrain"*, *"reject"* », *"constrain"*).
+ sec-temporal-isoyearmonthfromfields step 2:
+ 2. Let _overflow_ be ? ToTemporalOverflow(_options_).
+ sec-temporal.calendar.prototype.yearmonthfromfields step 6:
+ 6. Let _result_ be ? ISOYearMonthFromFields(_fields_, _options_).
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = new Temporal.Calendar("iso8601");
+
+const explicit = calendar.yearMonthFromFields({ year: 2000, month: 15 }, { overflow: undefined });
+TemporalHelpers.assertPlainYearMonth(explicit, 2000, 12, "M12", "default overflow is constrain");
+const implicit = calendar.yearMonthFromFields({ year: 2000, month: 15 }, {});
+TemporalHelpers.assertPlainYearMonth(implicit, 2000, 12, "M12", "default overflow is constrain");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/overflow-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/overflow-wrong-type.js
new file mode 100644
index 0000000000..422e9cc007
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/overflow-wrong-type.js
@@ -0,0 +1,27 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearmonthfromfields
+description: Type conversions for overflow option
+info: |
+ sec-getoption step 9.a:
+ a. Set _value_ to ? ToString(_value_).
+ sec-temporal-totemporaloverflow step 1:
+ 1. Return ? GetOption(_normalizedOptions_, *"overflow"*, « String », « *"constrain"*, *"reject"* », *"constrain"*).
+ sec-temporal-isoyearmonthfromfields step 2:
+ 2. Let _overflow_ be ? ToTemporalOverflow(_options_).
+ sec-temporal.calendar.prototype.yearmonthfromfields step 6:
+ 6. Let _result_ be ? ISOYearMonthFromFields(_fields_, _options_).
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = new Temporal.Calendar("iso8601");
+TemporalHelpers.checkStringOptionWrongType("overflow", "constrain",
+ (overflow) => calendar.yearMonthFromFields({ year: 2000, month: 5 }, { overflow }),
+ (result, descr) => TemporalHelpers.assertPlainYearMonth(result, 2000, 5, "M05", descr),
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/prop-desc.js
new file mode 100644
index 0000000000..b805c816df
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/prop-desc.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearmonthfromfields
+description: The "yearMonthFromFields" property of Temporal.Calendar.prototype
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+assert.sameValue(
+ typeof Temporal.Calendar.prototype.yearMonthFromFields,
+ "function",
+ "`typeof Calendar.prototype.yearMonthFromFields` is `function`"
+);
+
+verifyProperty(Temporal.Calendar.prototype, "yearMonthFromFields", {
+ writable: true,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/reference-day.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/reference-day.js
new file mode 100644
index 0000000000..5c1157cda8
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/reference-day.js
@@ -0,0 +1,41 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearmonthfromfields
+description: Reference ISO day is chosen to be the first of the calendar month
+info: |
+ 6.d. Perform ! CreateDataPropertyOrThrow(_fields_, *"day"*, *1*<sub>𝔽</sub>).
+ e. Let _result_ be ? CalendarDateToISO(_calendar_.[[Identifier]], _fields_, _options_).
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const cal = new Temporal.Calendar("iso8601");
+
+const result1 = cal.yearMonthFromFields({ year: 2023, monthCode: "M01", day: 13 });
+TemporalHelpers.assertPlainYearMonth(
+ result1,
+ 2023, 1, "M01",
+ "reference day is 1 even if day is given",
+ /* era = */ undefined, /* era year = */ undefined, /* reference day = */ 1
+);
+
+const result2 = cal.yearMonthFromFields({ year: 2021, monthCode: "M02", day: 50 }, { overflow: "constrain" });
+TemporalHelpers.assertPlainYearMonth(
+ result2,
+ 2021, 2, "M02",
+ "reference day is 1 even if day is out of range (overflow constrain)",
+ /* era = */ undefined, /* era year = */ undefined, /* reference day = */ 1
+);
+
+const result3 = cal.yearMonthFromFields({ year: 2021, monthCode: "M02", day: 50 }, { overflow: "reject" });
+TemporalHelpers.assertPlainYearMonth(
+ result3,
+ 2021, 2, "M02",
+ "reference day is 1 even if day is out of range (overflow reject)",
+ /* era = */ undefined, /* era year = */ undefined, /* reference day = */ 1
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/shell.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/shell.js
new file mode 100644
index 0000000000..eda1477282
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearMonthFromFields/shell.js
@@ -0,0 +1,24 @@
+// GENERATED, DO NOT EDIT
+// file: isConstructor.js
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: |
+ Test if a given function is a constructor function.
+defines: [isConstructor]
+features: [Reflect.construct]
+---*/
+
+function isConstructor(f) {
+ if (typeof f !== "function") {
+ throw new Test262Error("isConstructor invoked with a non-function value");
+ }
+
+ try {
+ Reflect.construct(function(){}, [], f);
+ } catch (e) {
+ return false;
+ }
+ return true;
+}
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-builtin-calendar-no-array-iteration.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-builtin-calendar-no-array-iteration.js
new file mode 100644
index 0000000000..7ec569149d
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-builtin-calendar-no-array-iteration.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearofweek
+description: >
+ Calling the method with a property bag argument with a builtin calendar causes
+ no observable array iteration when getting the calendar fields.
+features: [Temporal]
+---*/
+
+const arrayPrototypeSymbolIteratorOriginal = Array.prototype[Symbol.iterator];
+Array.prototype[Symbol.iterator] = function arrayIterator() {
+ throw new Test262Error("Array should not be iterated");
+}
+
+const instance = new Temporal.Calendar("iso8601");
+const arg = { year: 2000, month: 5, day: 2, calendar: "iso8601" };
+instance.yearOfWeek(arg);
+
+Array.prototype[Symbol.iterator] = arrayPrototypeSymbolIteratorOriginal;
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-calendar-datefromfields-called-with-null-prototype-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-calendar-datefromfields-called-with-null-prototype-fields.js
new file mode 100644
index 0000000000..3fa5c6e13f
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-calendar-datefromfields-called-with-null-prototype-fields.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearofweek
+description: >
+ Calendar.dateFromFields method is called with a null-prototype fields object
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarCheckFieldsPrototypePollution();
+const instance = new Temporal.Calendar("iso8601");
+const arg = { year: 2000, month: 5, day: 2, calendar };
+instance.yearOfWeek(arg);
+assert.sameValue(calendar.dateFromFieldsCallCount, 1, "dateFromFields should be called on the property bag's calendar");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-constructor-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-constructor-in-calendar-fields.js
new file mode 100644
index 0000000000..ce63ac519f
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-constructor-in-calendar-fields.js
@@ -0,0 +1,17 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.yearofweek
+description: If a calendar's fields() method returns a field named 'constructor', PrepareTemporalFields should throw a RangeError.
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarWithExtraFields(['constructor']);
+const arg = {year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar};
+const instance = new Temporal.Calendar("iso8601");
+
+assert.throws(RangeError, () => instance.yearOfWeek(arg));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-duplicate-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-duplicate-calendar-fields.js
new file mode 100644
index 0000000000..d564d1f73f
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-duplicate-calendar-fields.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.yearofweek
+description: If a calendar's fields() method returns duplicate field names, PrepareTemporalFields should throw a RangeError.
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+for (const extra_fields of [['foo', 'foo'], ['day'], ['month'], ['monthCode'], ['year']]) {
+ const calendar = TemporalHelpers.calendarWithExtraFields(extra_fields);
+ const arg = { year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar };
+ const instance = new Temporal.Calendar("iso8601");
+
+ assert.throws(RangeError, () => instance.yearOfWeek(arg));
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-leap-second.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-leap-second.js
new file mode 100644
index 0000000000..1e28b31f7c
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-leap-second.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearofweek
+description: Leap second is a valid ISO string for PlainDate
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+let arg = "2016-12-31T23:59:60";
+const result1 = instance.yearOfWeek(arg);
+assert.sameValue(
+ result1,
+ 2016,
+ "leap second is a valid ISO string for PlainDate"
+);
+
+arg = { year: 2016, month: 12, day: 31, hour: 23, minute: 59, second: 60 };
+const result2 = instance.yearOfWeek(arg);
+assert.sameValue(
+ result2,
+ 2016,
+ "second: 60 is ignored in property bag for PlainDate"
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-number.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-number.js
new file mode 100644
index 0000000000..6e3a05779d
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-number.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearofweek
+description: A number cannot be used in place of a Temporal.PlainDate
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const numbers = [
+ 1,
+ 19761118,
+ -19761118,
+ 1234567890,
+];
+
+for (const arg of numbers) {
+ assert.throws(
+ TypeError,
+ () => instance.yearOfWeek(arg),
+ 'Numbers cannot be used in place of an ISO string for PlainDate'
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-propertybag-calendar-case-insensitive.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-propertybag-calendar-case-insensitive.js
new file mode 100644
index 0000000000..208f4f763f
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-propertybag-calendar-case-insensitive.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearofweek
+description: The calendar name is case-insensitive
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const calendar = "IsO8601";
+
+const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+const result = instance.yearOfWeek(arg);
+assert.sameValue(result, 1976, "Calendar is case-insensitive");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-propertybag-calendar-leap-second.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-propertybag-calendar-leap-second.js
new file mode 100644
index 0000000000..fb54865fc1
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-propertybag-calendar-leap-second.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearofweek
+description: Leap second is a valid ISO string for a calendar in a property bag
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const calendar = "2016-12-31T23:59:60";
+
+const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+const result = instance.yearOfWeek(arg);
+assert.sameValue(
+ result,
+ 1976,
+ "leap second is a valid ISO string for calendar"
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-propertybag-calendar-number.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-propertybag-calendar-number.js
new file mode 100644
index 0000000000..c74d13eb85
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-propertybag-calendar-number.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearofweek
+description: A number as calendar in a property bag is not accepted
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const numbers = [
+ 1,
+ 19970327,
+ -19970327,
+ 1234567890,
+];
+
+for (const calendar of numbers) {
+ const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+ assert.throws(
+ TypeError,
+ () => instance.yearOfWeek(arg),
+ "Numbers cannot be used as a calendar"
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-propertybag-calendar-string.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-propertybag-calendar-string.js
new file mode 100644
index 0000000000..686ec25927
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-propertybag-calendar-string.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearofweek
+description: A calendar ID is valid input for Calendar
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const calendar = "iso8601";
+
+const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+const result = instance.yearOfWeek(arg);
+assert.sameValue(result, 1976, `Calendar created from string "${calendar}"`);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-propertybag-calendar-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-propertybag-calendar-wrong-type.js
new file mode 100644
index 0000000000..e05f76a918
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-propertybag-calendar-wrong-type.js
@@ -0,0 +1,46 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearofweek
+description: >
+ Appropriate error thrown when a calendar property from a property bag cannot
+ be converted to a calendar object or string
+features: [BigInt, Symbol, Temporal]
+---*/
+
+const timeZone = new Temporal.TimeZone("UTC");
+const instance = new Temporal.Calendar("iso8601");
+
+const primitiveTests = [
+ [null, "null"],
+ [true, "boolean"],
+ ["", "empty string"],
+ [1, "number that doesn't convert to a valid ISO string"],
+ [1n, "bigint"],
+];
+
+for (const [calendar, description] of primitiveTests) {
+ const arg = { year: 2019, monthCode: "M11", day: 1, calendar };
+ assert.throws(
+ typeof calendar === 'string' ? RangeError : TypeError,
+ () => instance.yearOfWeek(arg),
+ `${description} does not convert to a valid ISO string`
+ );
+}
+
+const typeErrorTests = [
+ [Symbol(), "symbol"],
+ [{}, "plain object that doesn't implement the protocol"],
+ [new Temporal.TimeZone("UTC"), "time zone instance"],
+ [Temporal.Calendar, "Temporal.Calendar, object"],
+ [Temporal.Calendar.prototype, "Temporal.Calendar.prototype, object"], // fails brand check in dateFromFields()
+];
+
+for (const [calendar, description] of typeErrorTests) {
+ const arg = { year: 2019, monthCode: "M11", day: 1, calendar };
+ assert.throws(TypeError, () => instance.yearOfWeek(arg), `${description} is not a valid property bag and does not convert to a string`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-propertybag-calendar-year-zero.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-propertybag-calendar-year-zero.js
new file mode 100644
index 0000000000..ad33245788
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-propertybag-calendar-year-zero.js
@@ -0,0 +1,27 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearofweek
+description: Negative zero, as an extended year, is rejected
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ "-000000-10-31",
+ "-000000-10-31T17:45",
+ "-000000-10-31T17:45Z",
+ "-000000-10-31T17:45+01:00",
+ "-000000-10-31T17:45+00:00[UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.yearOfWeek(arg),
+ "reject minus zero as extended year"
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-proto-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-proto-in-calendar-fields.js
new file mode 100644
index 0000000000..48e0ff8e18
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-proto-in-calendar-fields.js
@@ -0,0 +1,17 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.yearofweek
+description: If a calendar's fields() method returns a field named '__proto__', PrepareTemporalFields should throw a RangeError.
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarWithExtraFields(['__proto__']);
+const arg = {year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar};
+const instance = new Temporal.Calendar("iso8601");
+
+assert.throws(RangeError, () => instance.yearOfWeek(arg));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-calendar-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-calendar-annotation.js
new file mode 100644
index 0000000000..e278468ad2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-calendar-annotation.js
@@ -0,0 +1,33 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearofweek
+description: Various forms of calendar annotation; critical flag has no effect
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02[u-ca=iso8601]", "without time or time zone"],
+ ["2000-05-02[UTC][u-ca=iso8601]", "with time zone and no time"],
+ ["2000-05-02T15:23[u-ca=iso8601]", "without time zone"],
+ ["2000-05-02T15:23[UTC][u-ca=iso8601]", "with time zone"],
+ ["2000-05-02T15:23[!u-ca=iso8601]", "with ! and no time zone"],
+ ["2000-05-02T15:23[UTC][!u-ca=iso8601]", "with ! and time zone"],
+ ["2000-05-02T15:23[u-ca=iso8601][u-ca=discord]", "second annotation ignored"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.yearOfWeek(arg);
+
+ assert.sameValue(
+ result,
+ 2000,
+ `calendar annotation (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-critical-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-critical-unknown-annotation.js
new file mode 100644
index 0000000000..1feab2ed81
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-critical-unknown-annotation.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearofweek
+description: Unknown annotations with critical flag are rejected
+features: [Temporal]
+---*/
+
+const invalidStrings = [
+ "1970-01-01[!foo=bar]",
+ "1970-01-01T00:00[!foo=bar]",
+ "1970-01-01T00:00[UTC][!foo=bar]",
+ "1970-01-01T00:00[u-ca=iso8601][!foo=bar]",
+ "1970-01-01T00:00[UTC][!foo=bar][u-ca=iso8601]",
+ "1970-01-01T00:00[foo=bar][!_foo-bar0=Dont-Ignore-This-99999999999]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.yearOfWeek(arg),
+ `reject unknown annotation with critical flag: ${arg}`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-date-with-utc-offset.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-date-with-utc-offset.js
new file mode 100644
index 0000000000..38836a243e
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-date-with-utc-offset.js
@@ -0,0 +1,48 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearofweek
+description: UTC offset not valid with format that does not include a time
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const validStrings = [
+ "2000-05-02T00+00:00",
+ "2000-05-02T00+00:00[UTC]",
+ "2000-05-02T00+00:00[!UTC]",
+ "2000-05-02T00-02:30[America/St_Johns]",
+];
+
+for (const arg of validStrings) {
+ const result = instance.yearOfWeek(arg);
+
+ assert.sameValue(
+ result,
+ 2000,
+ `"${arg}" is a valid UTC offset with time for PlainDate`
+ );
+}
+
+const invalidStrings = [
+ "2022-09-15Z",
+ "2022-09-15Z[UTC]",
+ "2022-09-15Z[Europe/Vienna]",
+ "2022-09-15+00:00",
+ "2022-09-15+00:00[UTC]",
+ "2022-09-15-02:30",
+ "2022-09-15-02:30[America/St_Johns]",
+];
+
+for (const arg of invalidStrings) {
+ assert.throws(
+ RangeError,
+ () => instance.yearOfWeek(arg),
+ `"${arg}" UTC offset without time is not valid for PlainDate`
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-invalid.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-invalid.js
new file mode 100644
index 0000000000..b93efa8ca6
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-invalid.js
@@ -0,0 +1,64 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearofweek
+description: >
+ RangeError thrown if an invalid ISO string (or syntactically valid ISO string
+ that is not supported) is used as a PlainDate
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ // invalid ISO strings:
+ "",
+ "invalid iso8601",
+ "2020-01-00",
+ "2020-01-32",
+ "2020-02-30",
+ "2021-02-29",
+ "2020-00-01",
+ "2020-13-01",
+ "2020-01-01T",
+ "2020-01-01T25:00:00",
+ "2020-01-01T01:60:00",
+ "2020-01-01T01:60:61",
+ "2020-01-01junk",
+ "2020-01-01T00:00:00junk",
+ "2020-01-01T00:00:00+00:00junk",
+ "2020-01-01T00:00:00+00:00[UTC]junk",
+ "2020-01-01T00:00:00+00:00[UTC][u-ca=iso8601]junk",
+ "02020-01-01",
+ "2020-001-01",
+ "2020-01-001",
+ "2020-01-01T001",
+ "2020-01-01T01:001",
+ "2020-01-01T01:01:001",
+ // valid, but forms not supported in Temporal:
+ "2020-W01-1",
+ "2020-001",
+ "+0002020-01-01",
+ // valid, but this calendar must not exist:
+ "2020-01-01[u-ca=notexist]",
+ // may be valid in other contexts, but insufficient information for PlainDate:
+ "2020-01",
+ "+002020-01",
+ "01-01",
+ "2020-W01",
+ "P1Y",
+ "-P12Y",
+ // valid, but outside the supported range:
+ "-999999-01-01",
+ "+999999-01-01",
+];
+const instance = new Temporal.Calendar("iso8601");
+for (const arg of invalidStrings) {
+ assert.throws(
+ RangeError,
+ () => instance.yearOfWeek(arg),
+ `"${arg}" should not be a valid ISO string for a PlainDate`
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-multiple-calendar.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-multiple-calendar.js
new file mode 100644
index 0000000000..f584787616
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-multiple-calendar.js
@@ -0,0 +1,32 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearofweek
+description: >
+ More than one calendar annotation is not syntactical if any have the criical
+ flag
+features: [Temporal]
+---*/
+
+const invalidStrings = [
+ "1970-01-01[u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01[!u-ca=iso8601][u-ca=iso8601]",
+ "1970-01-01[UTC][u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01[u-ca=iso8601][foo=bar][!u-ca=iso8601]",
+ "1970-01-01T00:00[u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01T00:00[!u-ca=iso8601][u-ca=iso8601]",
+ "1970-01-01T00:00[UTC][u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01T00:00[u-ca=iso8601][foo=bar][!u-ca=iso8601]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.yearOfWeek(arg),
+ `reject more than one calendar annotation if any critical: ${arg}`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-multiple-time-zone.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-multiple-time-zone.js
new file mode 100644
index 0000000000..559c84c38c
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-multiple-time-zone.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearofweek
+description: More than one time zone annotation is not syntactical
+features: [Temporal]
+---*/
+
+const invalidStrings = [
+ "1970-01-01[UTC][UTC]",
+ "1970-01-01T00:00[UTC][UTC]",
+ "1970-01-01T00:00[!UTC][UTC]",
+ "1970-01-01T00:00[UTC][!UTC]",
+ "1970-01-01T00:00[UTC][u-ca=iso8601][UTC]",
+ "1970-01-01T00:00[UTC][foo=bar][UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.yearOfWeek(arg),
+ `reject more than one time zone annotation: ${arg}`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-time-separators.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-time-separators.js
new file mode 100644
index 0000000000..19820a2a93
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-time-separators.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearofweek
+description: Time separator in string argument can vary
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02T15:23", "uppercase T"],
+ ["2000-05-02t15:23", "lowercase T"],
+ ["2000-05-02 15:23", "space between date and time"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.yearOfWeek(arg);
+
+ assert.sameValue(
+ result,
+ 2000,
+ `variant time separators (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-time-zone-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-time-zone-annotation.js
new file mode 100644
index 0000000000..8cfe78c092
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-time-zone-annotation.js
@@ -0,0 +1,38 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearofweek
+description: Various forms of time zone annotation; critical flag has no effect
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02[Asia/Kolkata]", "named, with no time"],
+ ["2000-05-02[!Europe/Vienna]", "named, with ! and no time"],
+ ["2000-05-02[+00:00]", "numeric, with no time"],
+ ["2000-05-02[!-02:30]", "numeric, with ! and no time"],
+ ["2000-05-02T15:23[America/Sao_Paulo]", "named, with no offset"],
+ ["2000-05-02T15:23[!Asia/Tokyo]", "named, with ! and no offset"],
+ ["2000-05-02T15:23[-02:30]", "numeric, with no offset"],
+ ["2000-05-02T15:23[!+00:00]", "numeric, with ! and no offset"],
+ ["2000-05-02T15:23+00:00[America/New_York]", "named, with offset"],
+ ["2000-05-02T15:23+00:00[!UTC]", "named, with offset and !"],
+ ["2000-05-02T15:23+00:00[+01:00]", "numeric, with offset"],
+ ["2000-05-02T15:23+00:00[!-08:00]", "numeric, with offset and !"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.yearOfWeek(arg);
+
+ assert.sameValue(
+ result,
+ 2000,
+ `time zone annotation (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-unknown-annotation.js
new file mode 100644
index 0000000000..7778eec61f
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-unknown-annotation.js
@@ -0,0 +1,32 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearofweek
+description: Various forms of unknown annotation
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02[foo=bar]", "without time"],
+ ["2000-05-02T15:23[foo=bar]", "alone"],
+ ["2000-05-02T15:23[UTC][foo=bar]", "with time zone"],
+ ["2000-05-02T15:23[u-ca=iso8601][foo=bar]", "with calendar"],
+ ["2000-05-02T15:23[UTC][foo=bar][u-ca=iso8601]", "with time zone and calendar"],
+ ["2000-05-02T15:23[foo=bar][_foo-bar0=Ignore-This-999999999999]", "with another unknown annotation"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.yearOfWeek(arg);
+
+ assert.sameValue(
+ result,
+ 2000,
+ `unknown annotation (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-with-utc-designator.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-with-utc-designator.js
new file mode 100644
index 0000000000..bebc2b7b8c
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-with-utc-designator.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearofweek
+description: RangeError thrown if a string with UTC designator is used as a PlainDate
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ "2019-10-01T09:00:00Z",
+ "2019-10-01T09:00:00Z[UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.yearOfWeek(arg),
+ "String with UTC designator should not be valid as a PlainDate"
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string.js
new file mode 100644
index 0000000000..100982120b
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string.js
@@ -0,0 +1,39 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearofweek
+description: >
+ Temporal.Calendar.prototype.yearOfWeek will take an ISO 8601 date string and
+ return the ISO week calendar year of that date.
+features: [Temporal]
+---*/
+
+const cal = new Temporal.Calendar("iso8601");
+
+// The following week calendar years are taken from the table "Examples of
+// contemporary dates around New Year's Day" from
+// https://en.wikipedia.org/wiki/ISO_week_date#Relation_with_the_Gregorian_calendar
+
+assert.sameValue(cal.yearOfWeek("1977-01-01"), 1976, "1977-01-01 is in yearOfWeek 1976");
+assert.sameValue(cal.yearOfWeek("1977-01-02"), 1976, "1977-01-02 is in yearOfWeek 1976");
+assert.sameValue(cal.yearOfWeek("1977-12-31"), 1977, "1977-12-31 is in yearOfWeek 1977");
+assert.sameValue(cal.yearOfWeek("1978-01-01"), 1977, "1978-01-01 is in yearOfWeek 1977");
+assert.sameValue(cal.yearOfWeek("1978-01-02"), 1978, "1978-01-02 is in yearOfWeek 1978");
+assert.sameValue(cal.yearOfWeek("1978-12-31"), 1978, "1978-12-31 is in yearOfWeek 1978");
+assert.sameValue(cal.yearOfWeek("1979-01-01"), 1979, "1979-01-01 is in yearOfWeek 1979");
+assert.sameValue(cal.yearOfWeek("1979-12-30"), 1979, "1979-12-30 is in yearOfWeek 1979");
+assert.sameValue(cal.yearOfWeek("1979-12-31"), 1980, "1979-12-31 is in yearOfWeek 1980");
+assert.sameValue(cal.yearOfWeek("1980-01-01"), 1980, "1980-01-01 is in yearOfWeek 1980");
+assert.sameValue(cal.yearOfWeek("1980-12-28"), 1980, "1980-12-28 is in yearOfWeek 1980");
+assert.sameValue(cal.yearOfWeek("1980-12-29"), 1981, "1980-12-29 is in yearOfWeek 1981");
+assert.sameValue(cal.yearOfWeek("1980-12-30"), 1981, "1980-12-30 is in yearOfWeek 1981");
+assert.sameValue(cal.yearOfWeek("1980-12-31"), 1981, "1980-12-31 is in yearOfWeek 1981");
+assert.sameValue(cal.yearOfWeek("1981-01-01"), 1981, "1981-01-01 is in yearOfWeek 1981");
+assert.sameValue(cal.yearOfWeek("1981-12-31"), 1981, "1981-12-31 is in yearOfWeek 1981");
+assert.sameValue(cal.yearOfWeek("1982-01-01"), 1981, "1982-01-01 is in yearOfWeek 1981");
+assert.sameValue(cal.yearOfWeek("1982-01-02"), 1981, "1982-01-02 is in yearOfWeek 1981");
+assert.sameValue(cal.yearOfWeek("1982-01-03"), 1981, "1982-01-03 is in yearOfWeek 1981");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-wrong-type.js
new file mode 100644
index 0000000000..9d872b2e35
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-wrong-type.js
@@ -0,0 +1,43 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearofweek
+description: >
+ Appropriate error thrown when argument cannot be converted to a valid string
+ or property bag for PlainDate
+features: [BigInt, Symbol, Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const primitiveTests = [
+ [undefined, "undefined"],
+ [null, "null"],
+ [true, "boolean"],
+ ["", "empty string"],
+ [1, "number that doesn't convert to a valid ISO string"],
+ [1n, "bigint"],
+];
+
+for (const [arg, description] of primitiveTests) {
+ assert.throws(
+ typeof arg === 'string' ? RangeError : TypeError,
+ () => instance.yearOfWeek(arg),
+ `${description} does not convert to a valid ISO string`
+ );
+}
+
+const typeErrorTests = [
+ [Symbol(), "symbol"],
+ [{}, "plain object"],
+ [Temporal.PlainDate, "Temporal.PlainDate, object"],
+ [Temporal.PlainDate.prototype, "Temporal.PlainDate.prototype, object"],
+];
+
+for (const [arg, description] of typeErrorTests) {
+ assert.throws(TypeError, () => instance.yearOfWeek(arg), `${description} is not a valid property bag and does not convert to a string`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-convert.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-convert.js
new file mode 100644
index 0000000000..1e694bc160
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-convert.js
@@ -0,0 +1,22 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearofweek
+description: An exception from TimeZone#getOffsetNanosecondsFor() is propagated.
+features: [Temporal]
+---*/
+
+class TZ extends Temporal.TimeZone {
+ constructor() { super("UTC") }
+ getOffsetNanosecondsFor() { throw new Test262Error() }
+}
+
+const tz = new TZ();
+const arg = new Temporal.ZonedDateTime(0n, tz);
+const instance = new Temporal.Calendar("iso8601");
+
+assert.throws(Test262Error, () => instance.yearOfWeek(arg));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-slots.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-slots.js
new file mode 100644
index 0000000000..86f4d6326c
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-slots.js
@@ -0,0 +1,40 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearofweek
+description: Getters are not called when converting a ZonedDateTime to a PlainDate.
+includes: [compareArray.js]
+features: [Temporal]
+---*/
+
+const actual = [];
+const prototypeDescrs = Object.getOwnPropertyDescriptors(Temporal.ZonedDateTime.prototype);
+const getters = ["year", "month", "monthCode", "day", "hour", "minute", "second", "millisecond", "microsecond", "nanosecond", "calendar"];
+
+for (const property of getters) {
+ Object.defineProperty(Temporal.ZonedDateTime.prototype, property, {
+ get() {
+ actual.push(`get ${property}`);
+ const value = prototypeDescrs[property].get.call(this);
+ return {
+ toString() {
+ actual.push(`toString ${property}`);
+ return value.toString();
+ },
+ valueOf() {
+ actual.push(`valueOf ${property}`);
+ return value;
+ },
+ };
+ },
+ });
+}
+
+const arg = new Temporal.ZonedDateTime(0n, "UTC");
+const instance = new Temporal.Calendar("iso8601");
+instance.yearOfWeek(arg);
+assert.compareArray(actual, []);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js
new file mode 100644
index 0000000000..9277758fb4
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearofweek
+description: RangeError thrown if time zone reports an offset that is not an integer number of nanoseconds
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+[3600_000_000_000.5, NaN, -Infinity, Infinity].forEach((wrongOffset) => {
+ const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset);
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ assert.throws(RangeError, () => calendar.yearOfWeek(datetime));
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js
new file mode 100644
index 0000000000..f76c1b0ef3
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearofweek
+description: TypeError thrown if timeZone.getOffsetNanosecondsFor is not callable
+features: [BigInt, Symbol, Temporal, arrow-function]
+---*/
+
+[undefined, null, true, Math.PI, 'string', Symbol('sym'), 42n, {}].forEach((notCallable) => {
+ const timeZone = new Temporal.TimeZone("UTC");
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ timeZone.getOffsetNanosecondsFor = notCallable;
+ assert.throws(
+ TypeError,
+ () => calendar.yearOfWeek(datetime),
+ `Uncallable ${notCallable === null ? 'null' : typeof notCallable} getOffsetNanosecondsFor should throw TypeError`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js
new file mode 100644
index 0000000000..abdfc3a615
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearofweek
+description: RangeError thrown if time zone reports an offset that is out of range
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+[-86400_000_000_000, 86400_000_000_000].forEach((wrongOffset) => {
+ const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset);
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ assert.throws(RangeError, () => calendar.yearOfWeek(datetime));
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js
new file mode 100644
index 0000000000..2e48de6dbe
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearofweek
+description: TypeError thrown if time zone reports an offset that is not a Number
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+[
+ undefined,
+ null,
+ true,
+ "+01:00",
+ Symbol(),
+ 3600_000_000_000n,
+ {},
+ { valueOf() { return 3600_000_000_000; } },
+].forEach((wrongOffset) => {
+ const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset);
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ assert.throws(TypeError, () => calendar.yearOfWeek(datetime));
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/basic.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/basic.js
new file mode 100644
index 0000000000..6d003929f4
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/basic.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearofweek
+description: Basic tests for yearOfWeek().
+features: [Temporal]
+---*/
+
+const iso = Temporal.Calendar.from("iso8601");
+const res = 1994;
+assert.sameValue(iso.yearOfWeek(Temporal.PlainDate.from("1994-11-05")), res, "PlainDate");
+assert.sameValue(iso.yearOfWeek(Temporal.PlainDateTime.from("1994-11-05T08:15:30")), res, "PlainDateTime");
+assert.sameValue(iso.yearOfWeek({ year: 1994, month: 11, day: 5 }), res, "property bag");
+assert.sameValue(iso.yearOfWeek("1994-11-05"), res, "string");
+assert.throws(TypeError, () => iso.yearOfWeek({ year: 2000 }), "property bag with missing properties");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/branding.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/branding.js
new file mode 100644
index 0000000000..82cba7fbe4
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/branding.js
@@ -0,0 +1,27 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearofweek
+description: Throw a TypeError if the receiver is invalid
+features: [Symbol, Temporal]
+---*/
+
+const yearOfWeek = Temporal.Calendar.prototype.yearOfWeek;
+
+assert.sameValue(typeof yearOfWeek, "function");
+
+const args = [new Temporal.PlainDate(2021, 7, 20)];
+
+assert.throws(TypeError, () => yearOfWeek.apply(undefined, args), "undefined");
+assert.throws(TypeError, () => yearOfWeek.apply(null, args), "null");
+assert.throws(TypeError, () => yearOfWeek.apply(true, args), "true");
+assert.throws(TypeError, () => yearOfWeek.apply("", args), "empty string");
+assert.throws(TypeError, () => yearOfWeek.apply(Symbol(), args), "symbol");
+assert.throws(TypeError, () => yearOfWeek.apply(1, args), "1");
+assert.throws(TypeError, () => yearOfWeek.apply({}, args), "plain object");
+assert.throws(TypeError, () => yearOfWeek.apply(Temporal.Calendar, args), "Temporal.Calendar");
+assert.throws(TypeError, () => yearOfWeek.apply(Temporal.Calendar.prototype, args), "Temporal.Calendar.prototype");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/browser.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/browser.js
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/builtin.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/builtin.js
new file mode 100644
index 0000000000..af26883b52
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/builtin.js
@@ -0,0 +1,36 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearofweek
+description: >
+ Tests that Temporal.Calendar.prototype.yearOfWeek
+ meets the requirements for built-in objects defined by the
+ introduction of chapter 17 of the ECMAScript Language Specification.
+info: |
+ Built-in functions that are not constructors do not have a "prototype" property unless
+ otherwise specified in the description of a particular function.
+
+ Unless specified otherwise, a built-in object that is callable as a function is a built-in
+ function object with the characteristics described in 10.3. Unless specified otherwise, the
+ [[Extensible]] internal slot of a built-in object initially has the value true.
+
+ Unless otherwise specified every built-in function and every built-in constructor has the
+ Function prototype object [...] as the value of its [[Prototype]] internal slot.
+features: [Temporal]
+---*/
+
+assert.sameValue(Object.isExtensible(Temporal.Calendar.prototype.yearOfWeek),
+ true, "Built-in objects must be extensible.");
+
+assert.sameValue(Object.prototype.toString.call(Temporal.Calendar.prototype.yearOfWeek),
+ "[object Function]", "Object.prototype.toString");
+
+assert.sameValue(Object.getPrototypeOf(Temporal.Calendar.prototype.yearOfWeek),
+ Function.prototype, "prototype");
+
+assert.sameValue(Temporal.Calendar.prototype.yearOfWeek.hasOwnProperty("prototype"),
+ false, "prototype property");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/calendar-datefromfields-called-with-options-undefined.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/calendar-datefromfields-called-with-options-undefined.js
new file mode 100644
index 0000000000..3fee75ad1e
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/calendar-datefromfields-called-with-options-undefined.js
@@ -0,0 +1,18 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearofweek
+description: >
+ Calendar.dateFromFields method is called with undefined as the options value
+ when call originates internally
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions();
+calendar.yearOfWeek({ year: 2000, month: 5, day: 3, calendar });
+assert.sameValue(calendar.dateFromFieldsCallCount, 1);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/calendar-fields-iterable.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/calendar-fields-iterable.js
new file mode 100644
index 0000000000..a3d2aeb80f
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/calendar-fields-iterable.js
@@ -0,0 +1,35 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearofweek
+description: Verify the result of calendar.fields() is treated correctly.
+info: |
+ sec-temporal.calendar.prototype.yearofweek step 4:
+ 4. Let _date_ be ? ToTemporalDate(_dateOrDateTime_).
+ sec-temporal-totemporaldate step 2.c:
+ c. Let _fieldNames_ be ? CalendarFields(_calendar_, « *"day"*, *"month"*, *"monthCode"*, *"year"* »).
+ sec-temporal-calendarfields step 4:
+ 4. Let _result_ be ? IterableToListOfType(_fieldsArray_, « String »).
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const expected = [
+ "day",
+ "month",
+ "monthCode",
+ "year",
+];
+
+const calendar1 = TemporalHelpers.calendarFieldsIterable();
+const calendar2 = TemporalHelpers.calendarFieldsIterable();
+calendar1.yearOfWeek({ year: 2000, month: 5, day: 2, calendar: calendar2 });
+
+assert.sameValue(calendar1.fieldsCallCount, 0, "fields() method not called");
+assert.sameValue(calendar2.fieldsCallCount, 1, "fields() method called once");
+assert.compareArray(calendar2.fieldsCalledWith[0], expected, "fields() method called with correct args");
+assert(calendar2.iteratorExhausted[0], "iterated through the whole iterable");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/calendar-temporal-object.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/calendar-temporal-object.js
new file mode 100644
index 0000000000..461137a7d7
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/calendar-temporal-object.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearofweek
+description: Fast path for converting other Temporal objects to Temporal.Calendar by reading internal slots
+info: |
+ sec-temporal.calendar.prototype.yearofweek step 4:
+ 4. Let _date_ be ? ToTemporalDate(_dateOrDateTime_).
+ sec-temporal-totemporaldate step 2.c:
+ c. Let _calendar_ be ? GetTemporalCalendarWithISODefault(_item_).
+ sec-temporal-gettemporalcalendarwithisodefault step 2:
+ 2. Return ? ToTemporalCalendarWithISODefault(_calendar_).
+ sec-temporal-totemporalcalendarwithisodefault step 2:
+ 3. Return ? ToTemporalCalendar(_temporalCalendarLike_).
+ sec-temporal-totemporalcalendar step 1.a:
+ a. If _temporalCalendarLike_ has an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]], [[InitializedTemporalMonthDay]], [[InitializedTemporalYearMonth]], or [[InitializedTemporalZonedDateTime]] internal slot, then
+ i. Return _temporalCalendarLike_.[[Calendar]].
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+TemporalHelpers.checkToTemporalCalendarFastPath((temporalObject) => {
+ const calendar = new Temporal.Calendar("iso8601");
+ calendar.yearOfWeek({ year: 2000, month: 5, day: 2, calendar: temporalObject });
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/cross-year.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/cross-year.js
new file mode 100644
index 0000000000..1ca8d9baff
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/cross-year.js
@@ -0,0 +1,15 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearOfWeek
+description: yearOfWeek() where the result is different from the calendar year
+features: [Temporal]
+---*/
+
+const iso = Temporal.Calendar.from("iso8601");
+assert.sameValue(iso.yearOfWeek(Temporal.PlainDate.from("2019-12-31")), 2020, "next year");
+assert.sameValue(iso.yearOfWeek(Temporal.PlainDate.from("2021-01-01")), 2020, "previous year");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/infinity-throws-rangeerror.js
new file mode 100644
index 0000000000..10df67cf65
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/infinity-throws-rangeerror.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: Throws if any value in the property bag is Infinity or -Infinity
+esid: sec-temporal.calendar.prototype.yearofweek
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+const base = { year: 2000, month: 5, day: 2 };
+
+[Infinity, -Infinity].forEach((inf) => {
+ ["year", "month", "day"].forEach((prop) => {
+ assert.throws(RangeError, () => instance.yearOfWeek({ ...base, [prop]: inf }), `${prop} property cannot be ${inf}`);
+
+ const calls = [];
+ const obj = TemporalHelpers.toPrimitiveObserver(calls, inf, prop);
+ assert.throws(RangeError, () => instance.yearOfWeek({ ...base, [prop]: obj }));
+ assert.compareArray(calls, [`get ${prop}.valueOf`, `call ${prop}.valueOf`], "it fails after fetching the primitive value");
+ });
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/length.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/length.js
new file mode 100644
index 0000000000..ef513c2254
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/length.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearofweek
+description: Temporal.Calendar.prototype.yearOfWeek.length is 1
+info: |
+ Every built-in function object, including constructors, has a "length" property whose value is
+ an integer. Unless otherwise specified, this value is equal to the largest number of named
+ arguments shown in the subclause headings for the function description. Optional parameters
+ (which are indicated with brackets: [ ]) or rest parameters (which are shown using the form
+ «...name») are not included in the default argument count.
+
+ Unless otherwise specified, the "length" property of a built-in function object has the
+ attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+verifyProperty(Temporal.Calendar.prototype.yearOfWeek, "length", {
+ value: 1,
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/name.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/name.js
new file mode 100644
index 0000000000..4bbf63865c
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/name.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearofweek
+description: Temporal.Calendar.prototype.yearOfWeek.name is "yearOfWeek".
+info: |
+ Every built-in function object, including constructors, that is not identified as an anonymous
+ function has a "name" property whose value is a String. Unless otherwise specified, this value
+ is the name that is given to the function in this specification.
+
+ Unless otherwise specified, the "name" property of a built-in function object, if it exists,
+ has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+verifyProperty(Temporal.Calendar.prototype.yearOfWeek, "name", {
+ value: "yearOfWeek",
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/not-a-constructor.js
new file mode 100644
index 0000000000..33016b31bd
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/not-a-constructor.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearofweek
+description: >
+ Temporal.Calendar.prototype.yearOfWeek does not implement [[Construct]], is not new-able
+info: |
+ Built-in function objects that are not identified as constructors do not implement the
+ [[Construct]] internal method unless otherwise specified in the description of a particular
+ function.
+includes: [isConstructor.js]
+features: [Reflect.construct, Temporal]
+---*/
+
+assert.throws(TypeError, () => {
+ new Temporal.Calendar.prototype.yearOfWeek();
+}, "Calling as constructor");
+
+assert.sameValue(isConstructor(Temporal.Calendar.prototype.yearOfWeek), false,
+ "isConstructor(Temporal.Calendar.prototype.yearOfWeek)");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/prop-desc.js
new file mode 100644
index 0000000000..ddffa0dd35
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/prop-desc.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearofweek
+description: The "yearOfWeek" property of Temporal.Calendar.prototype
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+assert.sameValue(
+ typeof Temporal.Calendar.prototype.yearOfWeek,
+ "function",
+ "`typeof Calendar.prototype.yearOfWeek` is `function`"
+);
+
+verifyProperty(Temporal.Calendar.prototype, "yearOfWeek", {
+ writable: true,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/shell.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/shell.js
new file mode 100644
index 0000000000..eda1477282
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/shell.js
@@ -0,0 +1,24 @@
+// GENERATED, DO NOT EDIT
+// file: isConstructor.js
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: |
+ Test if a given function is a constructor function.
+defines: [isConstructor]
+features: [Reflect.construct]
+---*/
+
+function isConstructor(f) {
+ if (typeof f !== "function") {
+ throw new Test262Error("isConstructor invoked with a non-function value");
+ }
+
+ try {
+ Reflect.construct(function(){}, [], f);
+ } catch (e) {
+ return false;
+ }
+ return true;
+}
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/year-zero.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/year-zero.js
new file mode 100644
index 0000000000..c6a42fb11e
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/yearOfWeek/year-zero.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.yearofweek
+description: Negative zero, as an extended year, is rejected
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ "-000000-10-31",
+ "-000000-10-31T00:45",
+ "-000000-10-31T00:45+01:00",
+ "-000000-10-31T00:45+00:00[UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.yearOfWeek(arg),
+ "reject minus zero as extended year"
+ );
+});
+
+reportCompare(0, 0);