1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 var deepEq
= chrome
.test
.checkDeepEq
;
7 var expectedEventOrder
;
15 var initialized
= false;
19 function deepCopy(obj
) {
22 if (typeof(obj
) != 'object')
24 if (Array
.isArray(obj
)) {
25 var tmp_array
= new Array
;
26 for (var i
= 0; i
< obj
.length
; i
++) {
27 tmp_array
.push(deepCopy(obj
[i
]));
34 tmp_object
[p
] = deepCopy(obj
[p
]);
39 // data: array of expected events, each one is a dictionary:
40 // { label: "<unique identifier>",
41 // event: "<webnavigation event type>",
42 // details: { <expected details of the event> }
44 // order: an array of sequences, e.g. [ ["a", "b", "c"], ["d", "e"] ] means that
45 // event with label "a" needs to occur before event with label "b". The
46 // relative order of "a" and "d" does not matter.
47 function expect(data
, order
) {
48 expectedEventData
= data
;
49 capturedEventData
= [];
50 expectedEventOrder
= order
;
60 function checkExpectations() {
61 if (capturedEventData
.length
< expectedEventData
.length
) {
64 if (capturedEventData
.length
> expectedEventData
.length
) {
65 chrome
.test
.fail("Recorded too many events. " +
66 JSON
.stringify(capturedEventData
));
68 // We have ensured that capturedEventData contains exactly the same elements
69 // as expectedEventData. Now we need to verify the ordering.
70 // Step 1: build positions such that
71 // position[<event-label>]=<position of this event in capturedEventData>
74 capturedEventData
.forEach(function (event
) {
75 chrome
.test
.assertTrue(event
.hasOwnProperty("label"));
76 positions
[event
.label
] = curPos
;
79 // Step 2: check that elements arrived in correct order
80 expectedEventOrder
.forEach(function (order
) {
81 var previousLabel
= undefined;
82 order
.forEach(function (label
) {
83 if (previousLabel
=== undefined) {
84 previousLabel
= label
;
87 chrome
.test
.assertTrue(positions
[previousLabel
] < positions
[label
],
88 "Event " + previousLabel
+ " is supposed to arrive before " +
90 previousLabel
= label
;
93 chrome
.test
.succeed();
96 function captureEvent(name
, details
) {
97 if ('url' in details
) {
98 // Skip about:blank navigations
99 if (details
.url
== 'about:blank') {
102 // Strip query parameter as it is hard to predict.
103 details
.url
= details
.url
.replace(new RegExp('\\?[^#]*'), '');
105 // normalize details.
106 if ('timeStamp' in details
) {
107 details
.timeStamp
= 0;
109 if (('frameId' in details
) && (details
.frameId
!= 0)) {
110 if (frameIds
[details
.frameId
] === undefined) {
111 frameIds
[details
.frameId
] = nextFrameId
++;
113 details
.frameId
= frameIds
[details
.frameId
];
115 if (('parentFrameId' in details
) && (details
.parentFrameId
> 0)) {
116 if (frameIds
[details
.parentFrameId
] === undefined) {
117 frameIds
[details
.parentFrameId
] = nextFrameId
++;
119 details
.parentFrameId
= frameIds
[details
.parentFrameId
];
121 if (('sourceFrameId' in details
) && (details
.sourceFrameId
!= 0)) {
122 if (frameIds
[details
.sourceFrameId
] === undefined) {
123 frameIds
[details
.sourceFrameId
] = nextFrameId
++;
125 details
.sourceFrameId
= frameIds
[details
.sourceFrameId
];
127 if ('tabId' in details
) {
128 if (tabIds
[details
.tabId
] === undefined) {
129 tabIds
[details
.tabId
] = nextTabId
++;
131 details
.tabId
= tabIds
[details
.tabId
];
133 if ('sourceTabId' in details
) {
134 if (tabIds
[details
.sourceTabId
] === undefined) {
135 tabIds
[details
.sourceTabId
] = nextTabId
++;
137 details
.sourceTabId
= tabIds
[details
.sourceTabId
];
139 if ('replacedTabId' in details
) {
140 if (tabIds
[details
.replacedTabId
] === undefined) {
141 tabIds
[details
.replacedTabId
] = nextTabId
++;
143 details
.replacedTabId
= tabIds
[details
.replacedTabId
];
145 if ('processId' in details
) {
146 if (processIds
[details
.processId
] === undefined) {
147 processIds
[details
.processId
] = nextProcessId
++;
149 details
.processId
= processIds
[details
.processId
];
151 if ('sourceProcessId' in details
) {
152 if (processIds
[details
.sourceProcessId
] === undefined) {
153 processIds
[details
.sourceProcessId
] = nextProcessId
++;
155 details
.sourceProcessId
= processIds
[details
.sourceProcessId
];
159 console
.log("Received event '" + name
+ "':" + JSON
.stringify(details
));
161 // find |details| in expectedEventData
163 var label
= undefined;
164 expectedEventData
.forEach(function (exp
) {
165 if (exp
.event
== name
) {
168 if ('transitionQualifiers' in exp
.details
) {
169 var idx
= exp
.details
['transitionQualifiers'].indexOf(
170 'maybe_client_redirect');
172 exp_details
= deepCopy(exp
.details
);
173 exp_details
['transitionQualifiers'].splice(idx
, 1);
174 alt_details
= deepCopy(exp_details
);
175 alt_details
['transitionQualifiers'].push('client_redirect');
177 exp_details
= exp
.details
;
178 alt_details
= exp
.details
;
181 exp_details
= exp
.details
;
182 alt_details
= exp
.details
;
184 if (deepEq(exp_details
, details
) || deepEq(alt_details
, details
)) {
188 exp
.event
= undefined;
194 chrome
.test
.fail("Received unexpected event '" + name
+ "':" +
195 JSON
.stringify(details
));
197 capturedEventData
.push({label
: label
, event
: name
, details
: details
});
201 function initListeners() {
205 chrome
.webNavigation
.onBeforeNavigate
.addListener(
207 captureEvent("onBeforeNavigate", details
);
209 chrome
.webNavigation
.onCommitted
.addListener(
211 captureEvent("onCommitted", details
);
213 chrome
.webNavigation
.onDOMContentLoaded
.addListener(
215 captureEvent("onDOMContentLoaded", details
);
217 chrome
.webNavigation
.onCompleted
.addListener(
219 captureEvent("onCompleted", details
);
221 chrome
.webNavigation
.onCreatedNavigationTarget
.addListener(
223 captureEvent("onCreatedNavigationTarget", details
);
225 chrome
.webNavigation
.onReferenceFragmentUpdated
.addListener(
227 captureEvent("onReferenceFragmentUpdated", details
);
229 chrome
.webNavigation
.onErrorOccurred
.addListener(
231 captureEvent("onErrorOccurred", details
);
233 chrome
.webNavigation
.onTabReplaced
.addListener(
235 captureEvent("onTabReplaced", details
);
237 chrome
.webNavigation
.onHistoryStateUpdated
.addListener(
239 captureEvent("onHistoryStateUpdated", details
);
243 // Returns the usual order of navigation events.
244 function navigationOrder(prefix
) {
245 return [ prefix
+ "onBeforeNavigate",
246 prefix
+ "onCommitted",
247 prefix
+ "onDOMContentLoaded",
248 prefix
+ "onCompleted" ];
251 // Returns the constraints expressing that a frame is an iframe of another
253 function isIFrameOf(iframe
, main_frame
) {
254 return [ main_frame
+ "onCommitted",
255 iframe
+ "onBeforeNavigate",
256 iframe
+ "onCompleted",
257 main_frame
+ "onCompleted" ];
260 // Returns the constraint expressing that a frame was loaded by another.
261 function isLoadedBy(target
, source
) {
262 return [ source
+ "onDOMContentLoaded", target
+ "onBeforeNavigate"];