|
| 1 | +<!DOCTYPE html> |
| 2 | +<meta charset="utf-8"> |
| 3 | +<script src="../../../inspector/resources/inspector-test.js"></script> |
| 4 | +<script src="../debugger/resources/site-isolation-debugger-test-utilities.js"></script> |
| 5 | +<script src="resources/frame-timeline-test-utilities.js"></script> |
| 6 | +<script src="resources/timeline-events.js"></script> |
| 7 | +<script> |
| 8 | +function test() { |
| 9 | + let suite = InspectorTest.createAsyncSuite("SiteIsolation.Timeline.FrameTargetRecords"); |
| 10 | + |
| 11 | + let mainFrameTarget; |
| 12 | + let iframeTarget; |
| 13 | + |
| 14 | + function targetDescription(target) { |
| 15 | + if (target === mainFrameTarget) |
| 16 | + return "main frame target"; |
| 17 | + if (target === iframeTarget) |
| 18 | + return "cross-origin iframe target"; |
| 19 | + if (target === WI.mainTarget) |
| 20 | + return "page target"; |
| 21 | + return "unknown target"; |
| 22 | + } |
| 23 | + |
| 24 | + function expectRecordInRecording(record, startTime, endTime) { |
| 25 | + let description = targetDescription(record.target); |
| 26 | + InspectorTest.expectThat(record.startTime > 0, `Record from the ${description} should have a non-zero start time.`); |
| 27 | + InspectorTest.expectThat(startTime <= record.startTime && record.endTime <= endTime, `Record from the ${description} should be within the recording.`); |
| 28 | + } |
| 29 | + |
| 30 | + function expectNoScriptRecordsFromPageTarget(recording) { |
| 31 | + let scriptTimeline = recording.timelines.get(WI.TimelineRecord.Type.Script); |
| 32 | + // Garbage collections are reported by the page target's Heap domain. |
| 33 | + let pageTargetRecords = scriptTimeline.records.filter((record) => record.target === WI.mainTarget && record.eventType !== WI.ScriptTimelineRecord.EventType.GarbageCollected); |
| 34 | + InspectorTest.expectEqual(pageTargetRecords.length, 0, "No script records other than garbage collections should come from the page target."); |
| 35 | + } |
| 36 | + |
| 37 | + suite.addTestCase({ |
| 38 | + name: "SiteIsolation.Timeline.FrameTargetRecords.Domain", |
| 39 | + description: "Frame targets should have the Timeline domain, but not auto-capture.", |
| 40 | + async test() { |
| 41 | + mainFrameTarget = InspectorTest.mainFrameTarget; |
| 42 | + iframeTarget = await waitForFrameTargetForURLContaining("timeline-frame.html"); |
| 43 | + InspectorTest.expectNotNull(iframeTarget, "Should find the cross-origin iframe target."); |
| 44 | + InspectorTest.expectNotEqual(iframeTarget, mainFrameTarget, "The cross-origin iframe target should not be the main frame target."); |
| 45 | + |
| 46 | + for (let target of [mainFrameTarget, iframeTarget]) { |
| 47 | + let description = targetDescription(target); |
| 48 | + InspectorTest.expectThat(target.hasDomain("Timeline"), `The ${description} should have the Timeline domain.`); |
| 49 | + InspectorTest.expectFalse(target.hasCommand("Timeline.setAutoCaptureEnabled"), `The ${description} should not have Timeline.setAutoCaptureEnabled.`); |
| 50 | + } |
| 51 | + InspectorTest.expectThat(WI.mainTarget.hasCommand("Timeline.setAutoCaptureEnabled"), "The page target should still have Timeline.setAutoCaptureEnabled."); |
| 52 | + } |
| 53 | + }); |
| 54 | + |
| 55 | + suite.addTestCase({ |
| 56 | + name: "SiteIsolation.Timeline.FrameTargetRecords.Timers", |
| 57 | + description: "Timers in the main frame and the cross-origin iframe should be recorded by their own frame targets, and the recording should stop once both have stopped.", |
| 58 | + async test() { |
| 59 | + await FrameTimelineTest.startCapturing([mainFrameTarget, iframeTarget]); |
| 60 | + InspectorTest.pass("Both frame targets started tracking."); |
| 61 | + |
| 62 | + let recording = WI.timelineManager.activeRecording; |
| 63 | + let mainFrameRecordPromise = FrameTimelineTest.awaitScriptRecord(mainFrameTarget, WI.ScriptTimelineRecord.EventType.TimerFired); |
| 64 | + let iframeRecordPromise = FrameTimelineTest.awaitScriptRecord(iframeTarget, WI.ScriptTimelineRecord.EventType.TimerFired); |
| 65 | + await FrameTimelineTest.evaluateInTarget(mainFrameTarget, "fireTimer()"); |
| 66 | + await FrameTimelineTest.evaluateInTarget(iframeTarget, "fireTimer()"); |
| 67 | + let mainFrameRecord = await mainFrameRecordPromise; |
| 68 | + InspectorTest.pass("Recorded a timer from the main frame target."); |
| 69 | + let iframeRecord = await iframeRecordPromise; |
| 70 | + InspectorTest.pass("Recorded a timer from the cross-origin iframe target."); |
| 71 | + |
| 72 | + await FrameTimelineTest.stopCapturing(); |
| 73 | + InspectorTest.pass("Capturing stopped."); |
| 74 | + |
| 75 | + for (let target of [mainFrameTarget, iframeTarget]) |
| 76 | + InspectorTest.expectThat(FrameTimelineTest.didReportTrackingEvent("capturingStopped", target), `The ${targetDescription(target)} should report that Timeline stopped.`); |
| 77 | + |
| 78 | + expectRecordInRecording(mainFrameRecord, recording.startTime, recording.endTime); |
| 79 | + expectRecordInRecording(iframeRecord, recording.startTime, recording.endTime); |
| 80 | + expectNoScriptRecordsFromPageTarget(recording); |
| 81 | + |
| 82 | + let scriptTimeline = recording.timelines.get(WI.TimelineRecord.Type.Script); |
| 83 | + for (let target of [mainFrameTarget, iframeTarget]) |
| 84 | + InspectorTest.expectThat(scriptTimeline.targets.includes(target), `The Script timeline should include the ${targetDescription(target)}.`); |
| 85 | + } |
| 86 | + }); |
| 87 | + |
| 88 | + suite.addTestCase({ |
| 89 | + name: "SiteIsolation.Timeline.FrameTargetRecords.EventDispatch", |
| 90 | + description: "An event dispatched in the cross-origin iframe should be recorded by its frame target.", |
| 91 | + async test() { |
| 92 | + await FrameTimelineTest.startCapturing([iframeTarget]); |
| 93 | + |
| 94 | + let recording = WI.timelineManager.activeRecording; |
| 95 | + let recordPromise = FrameTimelineTest.awaitScriptRecord(iframeTarget, WI.ScriptTimelineRecord.EventType.EventDispatched); |
| 96 | + await FrameTimelineTest.evaluateInTarget(iframeTarget, "dispatchTestEvent()"); |
| 97 | + let record = await recordPromise; |
| 98 | + InspectorTest.expectEqual(record.details, "test-event", "Recorded the dispatch of the test event from the cross-origin iframe target."); |
| 99 | + |
| 100 | + await FrameTimelineTest.stopCapturing(); |
| 101 | + InspectorTest.pass("Capturing stopped."); |
| 102 | + |
| 103 | + expectRecordInRecording(record, recording.startTime, recording.endTime); |
| 104 | + expectNoScriptRecordsFromPageTarget(recording); |
| 105 | + } |
| 106 | + }); |
| 107 | + |
| 108 | + suite.addTestCase({ |
| 109 | + name: "SiteIsolation.Timeline.FrameTargetRecords.NoFallbackToPageTarget", |
| 110 | + description: "While a frame target's Timeline domain is enabled but not tracking, its records should not go to the page target, even when the page target is tracking.", |
| 111 | + async test() { |
| 112 | + FrameTimelineTest.clearTrackingEvents(); |
| 113 | + |
| 114 | + let activePromise = FrameTimelineTest.awaitCapturingState(WI.TimelineManager.CapturingState.Active); |
| 115 | + await WI.mainTarget.TimelineAgent.start(); |
| 116 | + await activePromise; |
| 117 | + InspectorTest.expectFalse(FrameTimelineTest.didReportTrackingEvent("capturingStarted", mainFrameTarget), "The main frame target should not be tracking."); |
| 118 | + |
| 119 | + let recording = WI.timelineManager.activeRecording; |
| 120 | + await mainFrameTarget.RuntimeAgent.evaluate.invoke({expression: "new Promise((resolve) => setTimeout(() => { timerFired(); resolve(); }))", objectGroup: "test", awaitPromise: true}); |
| 121 | + InspectorTest.pass("A timer fired in the main frame."); |
| 122 | + |
| 123 | + // The page target sends any record before it reports that it stopped, so the check below sees them all. |
| 124 | + let inactivePromise = FrameTimelineTest.awaitCapturingState(WI.TimelineManager.CapturingState.Inactive); |
| 125 | + await WI.mainTarget.TimelineAgent.stop(); |
| 126 | + await inactivePromise; |
| 127 | + InspectorTest.pass("Capturing stopped."); |
| 128 | + |
| 129 | + let scriptTimeline = recording.timelines.get(WI.TimelineRecord.Type.Script); |
| 130 | + let timerRecords = scriptTimeline.records.filter((record) => record.eventType === WI.ScriptTimelineRecord.EventType.TimerFired); |
| 131 | + InspectorTest.expectFalse(timerRecords.some((record) => record.target === WI.mainTarget), "The page target should not record the main frame's timer."); |
| 132 | + } |
| 133 | + }); |
| 134 | + |
| 135 | + suite.runTestCasesAndFinish(); |
| 136 | +} |
| 137 | +</script> |
| 138 | + |
| 139 | +<body onload="runTest()"> |
| 140 | +<p>Test that under Site Isolation, Timeline records are reported by the frame target of the frame that did the work, including a cross-origin iframe.</p> |
| 141 | +<iframe src="http://localhost:8000/site-isolation/inspector/timeline/resources/timeline-frame.html"></iframe> |
| 142 | +</body> |
0 commit comments