--- a/devtools/client/inspector/animation/test/browser.ini
+++ b/devtools/client/inspector/animation/test/browser.ini
@@ -1,21 +1,25 @@
[DEFAULT]
tags = devtools
subsuite = devtools
support-files =
+ current-time-scrubber_head.js
doc_custom_playback_rate.html
doc_frame_script.js
doc_multi_easings.html
doc_multi_keyframes.html
doc_multi_timings.html
doc_mutations_fast.html
doc_pseudo.html
doc_simple_animation.html
head.js
+ keyframes-graph_keyframe-marker_head.js
+ summary-graph_delay-sign_head.js
+ summary-graph_end-delay-sign_head.js
!/devtools/client/inspector/test/head.js
!/devtools/client/inspector/test/shared-head.js
!/devtools/client/shared/test/frame-script-utils.js
!/devtools/client/shared/test/shared-head.js
!/devtools/client/shared/test/telemetry-test-helpers.js
!/devtools/client/shared/test/test-actor-registry.js
!/devtools/client/shared/test/test-actor.js
@@ -30,25 +34,27 @@ support-files =
[browser_animation_animation-list_select.js]
[browser_animation_animation-target.js]
[browser_animation_animation-target_highlight.js]
[browser_animation_animation-target_select.js]
[browser_animation_animation-timeline-tick.js]
[browser_animation_css-transition-with-playstate-idle.js]
[browser_animation_current-time-label.js]
[browser_animation_current-time-scrubber.js]
+[browser_animation_current-time-scrubber-rtl.js]
[browser_animation_current-time-scrubber_each-different-creation-time-animations.js]
[browser_animation_empty_on_invalid_nodes.js]
[browser_animation_indication-bar.js]
[browser_animation_inspector_exists.js]
[browser_animation_keyframes-graph_computed-value-path-01.js]
[browser_animation_keyframes-graph_computed-value-path-02.js]
[browser_animation_keyframes-graph_computed-value-path_easing-hint.js]
skip-if = (verify && !debug)
[browser_animation_keyframes-graph_keyframe-marker.js]
+[browser_animation_keyframes-graph_keyframe-marker-rtl.js]
[browser_animation_keyframes-progress-bar.js]
[browser_animation_keyframes-progress-bar_after-resuming.js]
[browser_animation_logic_auto-stop.js]
[browser_animation_logic_avoid-updating-during-hiding.js]
[browser_animation_logic_created-time.js]
[browser_animation_logic_mutations.js]
[browser_animation_logic_mutations_fast.js]
[browser_animation_logic_scroll-amount.js]
@@ -59,14 +65,16 @@ skip-if = (verify && !debug)
[browser_animation_playback-rate-selector.js]
[browser_animation_pseudo-element.js]
[browser_animation_rewind-button.js]
[browser_animation_summary-graph_animation-name.js]
[browser_animation_summary-graph_compositor.js]
[browser_animation_summary-graph_computed-timing-path.js]
[browser_animation_summary-graph_computed-timing-path_different-timescale.js]
[browser_animation_summary-graph_delay-sign.js]
+[browser_animation_summary-graph_delay-sign-rtl.js]
[browser_animation_summary-graph_end-delay-sign.js]
+[browser_animation_summary-graph_end-delay-sign-rtl.js]
[browser_animation_summary-graph_effect-timing-path.js]
[browser_animation_summary-graph_layout-by-seek.js]
[browser_animation_summary-graph_negative-delay-path.js]
[browser_animation_summary-graph_negative-end-delay-path.js]
[browser_animation_summary-graph_tooltip.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/animation/test/browser_animation_current-time-scrubber-rtl.js
@@ -0,0 +1,16 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/* import-globals-from current-time-scrubber_head.js */
+
+// Test for CurrentTimeScrubber on RTL environment.
+
+add_task(async function() {
+ Services.scriptloader.loadSubScript(
+ CHROME_URL_ROOT + "current-time-scrubber_head.js", this);
+ await pushPref("intl.uidirection", 1);
+ // eslint-disable-next-line no-undef
+ await testCurrentTimeScrubber(true);
+});
--- a/devtools/client/inspector/animation/test/browser_animation_current-time-scrubber.js
+++ b/devtools/client/inspector/animation/test/browser_animation_current-time-scrubber.js
@@ -1,68 +1,12 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
-// Test for following CurrentTimeScrubber and CurrentTimeScrubberController components:
-// * element existence
-// * scrubber position validity
-// * make animations currentTime to change by click on the controller
-// * mouse drag on the scrubber
+/* import-globals-from current-time-scrubber_head.js */
add_task(async function() {
- await addTab(URL_ROOT + "doc_simple_animation.html");
- await removeAnimatedElementsExcept([".long"]);
- const { animationInspector, panel } = await openAnimationInspector();
-
- info("Checking scrubber controller existence");
- const controllerEl = panel.querySelector(".current-time-scrubber-area");
- ok(controllerEl, "scrubber controller should exist");
-
- info("Checking scrubber existence");
- const scrubberEl = controllerEl.querySelector(".current-time-scrubber");
- ok(scrubberEl, "scrubber should exist");
-
- info("Checking scrubber changes current time of animation and the position");
- const duration = animationInspector.state.timeScale.getDuration();
- await clickOnCurrentTimeScrubberController(animationInspector, panel, 0);
- assertAnimationsCurrentTime(animationInspector, 0);
- assertPosition(scrubberEl, controllerEl, 0, animationInspector);
-
- await clickOnCurrentTimeScrubberController(animationInspector, panel, 1);
- assertAnimationsCurrentTime(animationInspector, duration);
- assertPosition(scrubberEl, controllerEl, duration, animationInspector);
-
- await clickOnCurrentTimeScrubberController(animationInspector, panel, 0.5);
- assertAnimationsCurrentTime(animationInspector, duration * 0.5);
- assertPosition(scrubberEl, controllerEl, duration * 0.5, animationInspector);
-
- info("Checking current time scrubber position during running");
- // Running again
- await clickOnPauseResumeButton(animationInspector, panel);
- let previousX = scrubberEl.getBoundingClientRect().x;
- await wait(100);
- let currentX = scrubberEl.getBoundingClientRect().x;
- isnot(previousX, currentX, "Scrubber should be moved");
-
- info("Checking draggable on scrubber over animation list");
- await clickOnPauseResumeButton(animationInspector, panel);
- previousX = scrubberEl.getBoundingClientRect().x;
- await dragOnCurrentTimeScrubber(animationInspector, panel, 0.5, 2, 30);
- currentX = scrubberEl.getBoundingClientRect().x;
- isnot(previousX, currentX, "Scrubber should be draggable");
-
- info("Checking a behavior which mouse out from animation inspector area " +
- "during dragging from controller");
- await dragOnCurrentTimeScrubberController(animationInspector, panel, 0.5, 2);
- ok(!panel.querySelector(".animation-list-container")
- .classList.contains("active-scrubber"), "Click and DnD should be inactive");
+ Services.scriptloader.loadSubScript(
+ CHROME_URL_ROOT + "current-time-scrubber_head.js", this);
+ await testCurrentTimeScrubber();
});
-
-function assertPosition(scrubberEl, controllerEl, time, animationInspector) {
- const controllerBounds = controllerEl.getBoundingClientRect();
- const scrubberBounds = scrubberEl.getBoundingClientRect();
- const scrubberX = scrubberBounds.x + scrubberBounds.width / 2 - controllerBounds.x;
- const timeScale = animationInspector.state.timeScale;
- const expected = Math.round(time / timeScale.getDuration() * controllerBounds.width);
- is(scrubberX, expected, `Position should be ${ expected } at ${ time }ms`);
-}
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/animation/test/browser_animation_keyframes-graph_keyframe-marker-rtl.js
@@ -0,0 +1,12 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+add_task(async function() {
+ Services.scriptloader.loadSubScript(
+ CHROME_URL_ROOT + "keyframes-graph_keyframe-marker_head.js", this);
+ await pushPref("intl.uidirection", 1);
+ // eslint-disable-next-line no-undef
+ await testKeyframesGraphKeyframesMarker();
+});
--- a/devtools/client/inspector/animation/test/browser_animation_keyframes-graph_keyframe-marker.js
+++ b/devtools/client/inspector/animation/test/browser_animation_keyframes-graph_keyframe-marker.js
@@ -1,173 +1,11 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
-// Test for following keyframe marker.
-// * element existence
-// * title
-// * and marginInlineStart style
-
-const TEST_DATA = [
- {
- targetClass: "multi-types",
- properties: [
- {
- name: "background-color",
- expectedValues: [
- {
- title: "rgb(255, 0, 0)",
- marginInlineStart: "0%",
- },
- {
- title: "rgb(0, 255, 0)",
- marginInlineStart: "100%",
- }
- ],
- },
- {
- name: "background-repeat",
- expectedValues: [
- {
- title: "space round",
- marginInlineStart: "0%",
- },
- {
- title: "round space",
- marginInlineStart: "100%",
- }
- ],
- },
- {
- name: "font-size",
- expectedValues: [
- {
- title: "10px",
- marginInlineStart: "0%",
- },
- {
- title: "20px",
- marginInlineStart: "100%",
- }
- ],
- },
- {
- name: "margin-left",
- expectedValues: [
- {
- title: "0px",
- marginInlineStart: "0%",
- },
- {
- title: "100px",
- marginInlineStart: "100%",
- }
- ],
- },
- {
- name: "opacity",
- expectedValues: [
- {
- title: "0",
- marginInlineStart: "0%",
- },
- {
- title: "1",
- marginInlineStart: "100%",
- }
- ],
- },
- {
- name: "text-align",
- expectedValues: [
- {
- title: "right",
- marginInlineStart: "0%",
- },
- {
- title: "center",
- marginInlineStart: "100%",
- }
- ],
- },
- {
- name: "transform",
- expectedValues: [
- {
- title: "translate(0px)",
- marginInlineStart: "0%",
- },
- {
- title: "translate(100px)",
- marginInlineStart: "100%",
- }
- ],
- },
- ],
- },
- {
- targetClass: "narrow-offsets",
- properties: [
- {
- name: "opacity",
- expectedValues: [
- {
- title: "0",
- marginInlineStart: "0%",
- },
- {
- title: "1",
- marginInlineStart: "10%",
- },
- {
- title: "0",
- marginInlineStart: "13%",
- },
- {
- title: "1",
- marginInlineStart: "100%",
- },
- ],
- },
- ],
- }
-];
-
add_task(async function() {
- await addTab(URL_ROOT + "doc_multi_keyframes.html");
- await removeAnimatedElementsExcept(TEST_DATA.map(t => `.${ t.targetClass }`));
- const { animationInspector, panel } = await openAnimationInspector();
-
- for (const { properties, targetClass } of TEST_DATA) {
- info(`Checking keyframe marker for ${ targetClass }`);
- await clickOnAnimationByTargetSelector(animationInspector,
- panel, `.${ targetClass }`);
-
- for (const { name, expectedValues } of properties) {
- const testTarget = `${ name } in ${ targetClass }`;
- info(`Checking keyframe marker for ${ testTarget }`);
- info(`Checking keyframe marker existence for ${ testTarget }`);
- const markerEls = panel.querySelectorAll(`.${ name } .keyframe-marker-item`);
- is(markerEls.length, expectedValues.length,
- `Count of keyframe marker elements of ${ testTarget } ` +
- `should be ${ expectedValues.length }`);
-
- for (let i = 0; i < expectedValues.length; i++) {
- const hintTarget = `.keyframe-marker-item[${ i }] of ${ testTarget }`;
-
- info(`Checking ${ hintTarget }`);
- const markerEl = markerEls[i];
- const expectedValue = expectedValues[i];
-
- info(`Checking title in ${ hintTarget }`);
- is(markerEl.getAttribute("title"), expectedValue.title,
- `title in ${ hintTarget } should be ${ expectedValue.title }`);
-
- info(`Checking marginInlineStart style in ${ hintTarget }`);
- is(markerEl.style.marginInlineStart, expectedValue.marginInlineStart,
- `marginInlineStart in ${ hintTarget } should be ` +
- `${ expectedValue.marginInlineStart }`);
- }
- }
- }
+ Services.scriptloader.loadSubScript(
+ CHROME_URL_ROOT + "keyframes-graph_keyframe-marker_head.js", this);
+ // eslint-disable-next-line no-undef
+ await testKeyframesGraphKeyframesMarker();
});
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/animation/test/browser_animation_summary-graph_delay-sign-rtl.js
@@ -0,0 +1,12 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+add_task(async function() {
+ Services.scriptloader.loadSubScript(
+ CHROME_URL_ROOT + "summary-graph_delay-sign_head.js", this);
+ await pushPref("intl.uidirection", 1);
+ // eslint-disable-next-line no-undef
+ await testSummaryGraphDelaySign();
+});
--- a/devtools/client/inspector/animation/test/browser_animation_summary-graph_delay-sign.js
+++ b/devtools/client/inspector/animation/test/browser_animation_summary-graph_delay-sign.js
@@ -1,84 +1,11 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
-// Test for following DelaySign component works.
-// * element existance
-// * marginInlineStart position
-// * width
-// * additinal class
-
-const TEST_DATA = [
- {
- targetClass: "delay-positive",
- expectedResult: {
- marginInlineStart: "25%",
- width: "25%",
- },
- },
- {
- targetClass: "delay-negative",
- expectedResult: {
- additionalClass: "negative",
- marginInlineStart: "0%",
- width: "25%",
- },
- },
- {
- targetClass: "fill-backwards-with-delay-iterationstart",
- expectedResult: {
- additionalClass: "fill",
- marginInlineStart: "25%",
- width: "25%",
- },
- },
- {
- targetClass: "fill-both",
- },
- {
- targetClass: "fill-both-width-delay-iterationstart",
- expectedResult: {
- additionalClass: "fill",
- marginInlineStart: "25%",
- width: "25%",
- },
- },
- {
- targetClass: "keyframes-easing-step",
- },
-];
-
add_task(async function() {
- await addTab(URL_ROOT + "doc_multi_timings.html");
- await removeAnimatedElementsExcept(TEST_DATA.map(t => `.${ t.targetClass }`));
- const { panel } = await openAnimationInspector();
-
- for (const { targetClass, expectedResult } of TEST_DATA) {
- const animationItemEl =
- findAnimationItemElementsByTargetSelector(panel, `.${ targetClass }`);
-
- info(`Checking delay sign existance for ${ targetClass }`);
- const delaySignEl = animationItemEl.querySelector(".animation-delay-sign");
-
- if (expectedResult) {
- ok(delaySignEl, "The delay sign element should be in animation item element");
-
- is(delaySignEl.style.marginInlineStart, expectedResult.marginInlineStart,
- `marginInlineStart position should be ${ expectedResult.marginInlineStart }`);
- is(delaySignEl.style.width, expectedResult.width,
- `Width should be ${ expectedResult.width }`);
-
- if (expectedResult.additionalClass) {
- ok(delaySignEl.classList.contains(expectedResult.additionalClass),
- `delay sign element should have ${ expectedResult.additionalClass } class`);
- } else {
- ok(!delaySignEl.classList.contains(expectedResult.additionalClass),
- "delay sign element should not have " +
- `${ expectedResult.additionalClass } class`);
- }
- } else {
- ok(!delaySignEl, "The delay sign element should not be in animation item element");
- }
- }
+ Services.scriptloader.loadSubScript(
+ CHROME_URL_ROOT + "summary-graph_delay-sign_head.js", this);
+ // eslint-disable-next-line no-undef
+ await testSummaryGraphDelaySign();
});
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/animation/test/browser_animation_summary-graph_end-delay-sign-rtl.js
@@ -0,0 +1,13 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/* import-globals-from summary-graph_end-delay-sign_head.js */
+
+add_task(async function() {
+ Services.scriptloader.loadSubScript(
+ CHROME_URL_ROOT + "summary-graph_end-delay-sign_head.js", this);
+ await pushPref("intl.uidirection", 1);
+ await testSummaryGraphEndDelaySign();
+});
--- a/devtools/client/inspector/animation/test/browser_animation_summary-graph_end-delay-sign.js
+++ b/devtools/client/inspector/animation/test/browser_animation_summary-graph_end-delay-sign.js
@@ -1,77 +1,11 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
-// Test for following EndDelaySign component works.
-// * element existance
-// * marginInlineStart position
-// * width
-// * additinal class
-
-const TEST_DATA = [
- {
- targetClass: "enddelay-positive",
- expectedResult: {
- marginInlineStart: "75%",
- width: "25%",
- },
- },
- {
- targetClass: "enddelay-negative",
- expectedResult: {
- additionalClass: "negative",
- marginInlineStart: "50%",
- width: "25%",
- },
- },
- {
- targetClass: "enddelay-with-fill-forwards",
- expectedResult: {
- additionalClass: "fill",
- marginInlineStart: "75%",
- width: "25%",
- },
- },
- {
- targetClass: "enddelay-with-iterations-infinity",
- },
- {
- targetClass: "delay-negative",
- },
-];
-
add_task(async function() {
- await addTab(URL_ROOT + "doc_multi_timings.html");
- await removeAnimatedElementsExcept(TEST_DATA.map(t => `.${ t.targetClass }`));
- const { panel } = await openAnimationInspector();
-
- for (const { targetClass, expectedResult } of TEST_DATA) {
- const animationItemEl =
- findAnimationItemElementsByTargetSelector(panel, `.${ targetClass }`);
-
- info(`Checking endDelay sign existance for ${ targetClass }`);
- const endDelaySignEl = animationItemEl.querySelector(".animation-end-delay-sign");
-
- if (expectedResult) {
- ok(endDelaySignEl, "The endDelay sign element should be in animation item element");
-
- is(endDelaySignEl.style.marginInlineStart, expectedResult.marginInlineStart,
- `marginInlineStart position should be ${ expectedResult.marginInlineStart }`);
- is(endDelaySignEl.style.width, expectedResult.width,
- `Width should be ${ expectedResult.width }`);
-
- if (expectedResult.additionalClass) {
- ok(endDelaySignEl.classList.contains(expectedResult.additionalClass),
- `endDelay sign element should have ${ expectedResult.additionalClass } class`);
- } else {
- ok(!endDelaySignEl.classList.contains(expectedResult.additionalClass),
- "endDelay sign element should not have " +
- `${ expectedResult.additionalClass } class`);
- }
- } else {
- ok(!endDelaySignEl,
- "The endDelay sign element should not be in animation item element");
- }
- }
+ Services.scriptloader.loadSubScript(
+ CHROME_URL_ROOT + "summary-graph_end-delay-sign_head.js", this);
+ // eslint-disable-next-line no-undef
+ await testSummaryGraphEndDelaySign();
});
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/animation/test/current-time-scrubber_head.js
@@ -0,0 +1,80 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/* import-globals-from head.js */
+
+// Test for following CurrentTimeScrubber and CurrentTimeScrubberController components:
+// * element existence
+// * scrubber position validity
+// * make animations currentTime to change by click on the controller
+// * mouse drag on the scrubber
+
+// eslint-disable-next-line no-unused-vars
+async function testCurrentTimeScrubber(isRTL) {
+ await addTab(URL_ROOT + "doc_simple_animation.html");
+ await removeAnimatedElementsExcept([".long"]);
+ const { animationInspector, panel } = await openAnimationInspector();
+
+ info("Checking scrubber controller existence");
+ const controllerEl = panel.querySelector(".current-time-scrubber-area");
+ ok(controllerEl, "scrubber controller should exist");
+
+ info("Checking scrubber existence");
+ const scrubberEl = controllerEl.querySelector(".current-time-scrubber");
+ ok(scrubberEl, "scrubber should exist");
+
+ info("Checking scrubber changes current time of animation and the position");
+ const duration = animationInspector.state.timeScale.getDuration();
+ await clickOnCurrentTimeScrubberController(animationInspector,
+ panel,
+ isRTL ? 1 : 0);
+ assertAnimationsCurrentTime(animationInspector, 0);
+ assertPosition(scrubberEl,
+ controllerEl,
+ isRTL ? duration : 0,
+ animationInspector);
+ await clickOnCurrentTimeScrubberController(animationInspector,
+ panel,
+ isRTL ? 0 : 1);
+ assertAnimationsCurrentTime(animationInspector, duration);
+ assertPosition(scrubberEl,
+ controllerEl,
+ isRTL ? 0 : duration,
+ animationInspector);
+
+ await clickOnCurrentTimeScrubberController(animationInspector, panel, 0.5);
+ assertAnimationsCurrentTime(animationInspector, duration * 0.5);
+ assertPosition(scrubberEl, controllerEl, duration * 0.5, animationInspector);
+
+ info("Checking current time scrubber position during running");
+ // Running again
+ await clickOnPauseResumeButton(animationInspector, panel);
+ let previousX = scrubberEl.getBoundingClientRect().x;
+ await wait(100);
+ let currentX = scrubberEl.getBoundingClientRect().x;
+ isnot(previousX, currentX, "Scrubber should be moved");
+
+ info("Checking draggable on scrubber over animation list");
+ await clickOnPauseResumeButton(animationInspector, panel);
+ previousX = scrubberEl.getBoundingClientRect().x;
+ await dragOnCurrentTimeScrubber(animationInspector, panel, 0.5, 2, 30);
+ currentX = scrubberEl.getBoundingClientRect().x;
+ isnot(previousX, currentX, "Scrubber should be draggable");
+
+ info("Checking a behavior which mouse out from animation inspector area " +
+ "during dragging from controller");
+ await dragOnCurrentTimeScrubberController(animationInspector, panel, 0.5, 2);
+ ok(!panel.querySelector(".animation-list-container")
+ .classList.contains("active-scrubber"), "Click and DnD should be inactive");
+}
+
+function assertPosition(scrubberEl, controllerEl, time, animationInspector) {
+ const controllerBounds = controllerEl.getBoundingClientRect();
+ const scrubberBounds = scrubberEl.getBoundingClientRect();
+ const scrubberX = scrubberBounds.x + scrubberBounds.width / 2 - controllerBounds.x;
+ const timeScale = animationInspector.state.timeScale;
+ const expected = Math.round(time / timeScale.getDuration() * controllerBounds.width);
+ is(scrubberX, expected, `Position should be ${ expected } at ${ time }ms`);
+}
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/animation/test/keyframes-graph_keyframe-marker_head.js
@@ -0,0 +1,182 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/* import-globals-from head.js */
+
+// Test for following keyframe marker.
+// * element existence
+// * title
+// * and marginInlineStart style
+
+const KEYFRAMES_TEST_DATA = [
+ {
+ targetClass: "multi-types",
+ properties: [
+ {
+ name: "background-color",
+ expectedValues: [
+ {
+ title: "rgb(255, 0, 0)",
+ marginInlineStart: "0%",
+ },
+ {
+ title: "rgb(0, 255, 0)",
+ marginInlineStart: "100%",
+ }
+ ],
+ },
+ {
+ name: "background-repeat",
+ expectedValues: [
+ {
+ title: "space round",
+ marginInlineStart: "0%",
+ },
+ {
+ title: "round space",
+ marginInlineStart: "100%",
+ }
+ ],
+ },
+ {
+ name: "font-size",
+ expectedValues: [
+ {
+ title: "10px",
+ marginInlineStart: "0%",
+ },
+ {
+ title: "20px",
+ marginInlineStart: "100%",
+ }
+ ],
+ },
+ {
+ name: "margin-left",
+ expectedValues: [
+ {
+ title: "0px",
+ marginInlineStart: "0%",
+ },
+ {
+ title: "100px",
+ marginInlineStart: "100%",
+ }
+ ],
+ },
+ {
+ name: "opacity",
+ expectedValues: [
+ {
+ title: "0",
+ marginInlineStart: "0%",
+ },
+ {
+ title: "1",
+ marginInlineStart: "100%",
+ }
+ ],
+ },
+ {
+ name: "text-align",
+ expectedValues: [
+ {
+ title: "right",
+ marginInlineStart: "0%",
+ },
+ {
+ title: "center",
+ marginInlineStart: "100%",
+ }
+ ],
+ },
+ {
+ name: "transform",
+ expectedValues: [
+ {
+ title: "translate(0px)",
+ marginInlineStart: "0%",
+ },
+ {
+ title: "translate(100px)",
+ marginInlineStart: "100%",
+ }
+ ],
+ },
+ ],
+ },
+ {
+ targetClass: "narrow-offsets",
+ properties: [
+ {
+ name: "opacity",
+ expectedValues: [
+ {
+ title: "0",
+ marginInlineStart: "0%",
+ },
+ {
+ title: "1",
+ marginInlineStart: "10%",
+ },
+ {
+ title: "0",
+ marginInlineStart: "13%",
+ },
+ {
+ title: "1",
+ marginInlineStart: "100%",
+ },
+ ],
+ },
+ ],
+ }
+];
+
+/**
+ * Do test for keyframes-graph_keyframe-marker-ltf/rtl.
+ *
+ * @param {Array} testData
+ */
+// eslint-disable-next-line no-unused-vars
+async function testKeyframesGraphKeyframesMarker() {
+ await addTab(URL_ROOT + "doc_multi_keyframes.html");
+ await removeAnimatedElementsExcept(KEYFRAMES_TEST_DATA.map(t => `.${ t.targetClass }`));
+ const { animationInspector, panel } = await openAnimationInspector();
+
+ for (const { properties, targetClass } of KEYFRAMES_TEST_DATA) {
+ info(`Checking keyframe marker for ${ targetClass }`);
+ await clickOnAnimationByTargetSelector(animationInspector,
+ panel, `.${ targetClass }`);
+
+ for (const { name, expectedValues } of properties) {
+ const testTarget = `${ name } in ${ targetClass }`;
+ info(`Checking keyframe marker for ${ testTarget }`);
+ info(`Checking keyframe marker existence for ${ testTarget }`);
+ const markerEls = panel.querySelectorAll(`.${ name } .keyframe-marker-item`);
+ is(markerEls.length, expectedValues.length,
+ `Count of keyframe marker elements of ${ testTarget } ` +
+ `should be ${ expectedValues.length }`);
+
+ for (let i = 0; i < expectedValues.length; i++) {
+ const hintTarget = `.keyframe-marker-item[${ i }] of ${ testTarget }`;
+
+ info(`Checking ${ hintTarget }`);
+ const markerEl = markerEls[i];
+ const expectedValue = expectedValues[i];
+
+ info(`Checking title in ${ hintTarget }`);
+ is(markerEl.getAttribute("title"), expectedValue.title,
+ `title in ${ hintTarget } should be ${ expectedValue.title }`);
+
+ info(`Checking marginInlineStart style in ${ hintTarget }`);
+ is(markerEl.style.marginInlineStart, expectedValue.marginInlineStart,
+ `marginInlineStart in ${ hintTarget } should be ` +
+ `${ expectedValue.marginInlineStart }`);
+ }
+ }
+ }
+}
+
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/animation/test/summary-graph_delay-sign_head.js
@@ -0,0 +1,87 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/* import-globals-from head.js */
+
+// Test for following DelaySign component works.
+// * element existance
+// * marginInlineStart position
+// * width
+// * additinal class
+
+const TEST_DATA = [
+ {
+ targetClass: "delay-positive",
+ expectedResult: {
+ marginInlineStart: "25%",
+ width: "25%",
+ },
+ },
+ {
+ targetClass: "delay-negative",
+ expectedResult: {
+ additionalClass: "negative",
+ marginInlineStart: "0%",
+ width: "25%",
+ },
+ },
+ {
+ targetClass: "fill-backwards-with-delay-iterationstart",
+ expectedResult: {
+ additionalClass: "fill",
+ marginInlineStart: "25%",
+ width: "25%",
+ },
+ },
+ {
+ targetClass: "fill-both",
+ },
+ {
+ targetClass: "fill-both-width-delay-iterationstart",
+ expectedResult: {
+ additionalClass: "fill",
+ marginInlineStart: "25%",
+ width: "25%",
+ },
+ },
+ {
+ targetClass: "keyframes-easing-step",
+ },
+];
+
+// eslint-disable-next-line no-unused-vars
+async function testSummaryGraphDelaySign() {
+ await addTab(URL_ROOT + "doc_multi_timings.html");
+ await removeAnimatedElementsExcept(TEST_DATA.map(t => `.${ t.targetClass }`));
+ const { panel } = await openAnimationInspector();
+
+ for (const { targetClass, expectedResult } of TEST_DATA) {
+ const animationItemEl =
+ findAnimationItemElementsByTargetSelector(panel, `.${ targetClass }`);
+
+ info(`Checking delay sign existance for ${ targetClass }`);
+ const delaySignEl = animationItemEl.querySelector(".animation-delay-sign");
+
+ if (expectedResult) {
+ ok(delaySignEl, "The delay sign element should be in animation item element");
+
+ is(delaySignEl.style.marginInlineStart, expectedResult.marginInlineStart,
+ `marginInlineStart position should be ${ expectedResult.marginInlineStart }`);
+ is(delaySignEl.style.width, expectedResult.width,
+ `Width should be ${ expectedResult.width }`);
+
+ if (expectedResult.additionalClass) {
+ ok(delaySignEl.classList.contains(expectedResult.additionalClass),
+ `delay sign element should have ${ expectedResult.additionalClass } class`);
+ } else {
+ ok(!delaySignEl.classList.contains(expectedResult.additionalClass),
+ "delay sign element should not have " +
+ `${ expectedResult.additionalClass } class`);
+ }
+ } else {
+ ok(!delaySignEl, "The delay sign element should not be in animation item element");
+ }
+ }
+}
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/animation/test/summary-graph_end-delay-sign_head.js
@@ -0,0 +1,80 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/* import-globals-from head.js */
+
+// Test for following EndDelaySign component works.
+// * element existance
+// * marginInlineStart position
+// * width
+// * additinal class
+
+const TEST_DATA = [
+ {
+ targetClass: "enddelay-positive",
+ expectedResult: {
+ marginInlineStart: "75%",
+ width: "25%",
+ },
+ },
+ {
+ targetClass: "enddelay-negative",
+ expectedResult: {
+ additionalClass: "negative",
+ marginInlineStart: "50%",
+ width: "25%",
+ },
+ },
+ {
+ targetClass: "enddelay-with-fill-forwards",
+ expectedResult: {
+ additionalClass: "fill",
+ marginInlineStart: "75%",
+ width: "25%",
+ },
+ },
+ {
+ targetClass: "enddelay-with-iterations-infinity",
+ },
+ {
+ targetClass: "delay-negative",
+ },
+];
+
+// eslint-disable-next-line no-unused-vars
+async function testSummaryGraphEndDelaySign() {
+ await addTab(URL_ROOT + "doc_multi_timings.html");
+ await removeAnimatedElementsExcept(TEST_DATA.map(t => `.${ t.targetClass }`));
+ const { panel } = await openAnimationInspector();
+
+ for (const { targetClass, expectedResult } of TEST_DATA) {
+ const animationItemEl =
+ findAnimationItemElementsByTargetSelector(panel, `.${ targetClass }`);
+
+ info(`Checking endDelay sign existance for ${ targetClass }`);
+ const endDelaySignEl = animationItemEl.querySelector(".animation-end-delay-sign");
+
+ if (expectedResult) {
+ ok(endDelaySignEl, "The endDelay sign element should be in animation item element");
+
+ is(endDelaySignEl.style.marginInlineStart, expectedResult.marginInlineStart,
+ `marginInlineStart position should be ${ expectedResult.marginInlineStart }`);
+ is(endDelaySignEl.style.width, expectedResult.width,
+ `Width should be ${ expectedResult.width }`);
+
+ if (expectedResult.additionalClass) {
+ ok(endDelaySignEl.classList.contains(expectedResult.additionalClass),
+ `endDelay sign element should have ${ expectedResult.additionalClass } class`);
+ } else {
+ ok(!endDelaySignEl.classList.contains(expectedResult.additionalClass),
+ "endDelay sign element should not have " +
+ `${ expectedResult.additionalClass } class`);
+ }
+ } else {
+ ok(!endDelaySignEl,
+ "The endDelay sign element should not be in animation item element");
+ }
+ }
+}
--- a/devtools/client/themes/animation.css
+++ b/devtools/client/themes/animation.css
@@ -101,26 +101,32 @@ select.playback-rate-selector.devtools-b
}
/* Current Time Scrubber */
.current-time-scrubber-area {
grid-column: 2 / 3;
z-index: 2;
}
-.current-time-scrubber-area::before {
+.current-time-scrubber-area:dir(ltr)::before,
+.current-time-scrubber-area:dir(rtl)::after {
content: "";
cursor: col-resize;
height: var(--devtools-toolbar-height);
pointer-events: auto;
position: absolute;
/* In order to click on edge of current-time-scrubber-controller element */
width: calc(100% + 1px);
}
+.current-time-scrubber-area:dir(rtl)::after {
+ /* In order to click on the start edge of current-time-scrubber-area element on RTL */
+ margin-inline-start: -1px;
+}
+
.indication-bar.current-time-scrubber {
cursor: col-resize;
pointer-events: auto;
width: 12px;
transform: translateX(-6px);
}
.indication-bar.current-time-scrubber:dir(rtl) {