|
1 /** |
|
2 * Any copyright is dedicated to the Public Domain. |
|
3 * http://creativecommons.org/publicdomain/zero/1.0/ |
|
4 */ |
|
5 |
|
6 var testGenerator = testSteps(); |
|
7 |
|
8 function testSteps() |
|
9 { |
|
10 // Test object stores |
|
11 |
|
12 const name = "test_complex_keyPaths"; |
|
13 const keyPaths = [ |
|
14 { keyPath: "id", value: { id: 5 }, key: 5 }, |
|
15 { keyPath: "id", value: { id: "14", iid: 12 }, key: "14" }, |
|
16 { keyPath: "id", value: { iid: "14", id: 12 }, key: 12 }, |
|
17 { keyPath: "id", value: {} }, |
|
18 { keyPath: "id", value: { id: {} } }, |
|
19 { keyPath: "id", value: { id: /x/ } }, |
|
20 { keyPath: "id", value: 2 }, |
|
21 { keyPath: "id", value: undefined }, |
|
22 { keyPath: "foo.id", value: { foo: { id: 7 } }, key: 7 }, |
|
23 { keyPath: "foo.id", value: { id: 7, foo: { id: "asdf" } }, key: "asdf" }, |
|
24 { keyPath: "foo.id", value: { foo: { id: undefined } } }, |
|
25 { keyPath: "foo.id", value: { foo: 47 } }, |
|
26 { keyPath: "foo.id", value: {} }, |
|
27 { keyPath: "", value: "foopy", key: "foopy" }, |
|
28 { keyPath: "", value: 2, key: 2 }, |
|
29 { keyPath: "", value: undefined }, |
|
30 { keyPath: "", value: { id: 12 } }, |
|
31 { keyPath: "", value: /x/ }, |
|
32 { keyPath: "foo.bar", value: { baz: 1, foo: { baz2: 2, bar: "xo" } }, key: "xo" }, |
|
33 { keyPath: "foo.bar.baz", value: { foo: { bar: { bazz: 16, baz: 17 } } }, key: 17 }, |
|
34 { keyPath: "foo..id", exception: true }, |
|
35 { keyPath: "foo.", exception: true }, |
|
36 { keyPath: "fo o", exception: true }, |
|
37 { keyPath: "foo ", exception: true }, |
|
38 { keyPath: "foo[bar]",exception: true }, |
|
39 { keyPath: "foo[1]", exception: true }, |
|
40 { keyPath: "$('id').stuff", exception: true }, |
|
41 { keyPath: "foo.2.bar", exception: true }, |
|
42 { keyPath: "foo. .bar", exception: true }, |
|
43 { keyPath: ".bar", exception: true }, |
|
44 { keyPath: [], exception: true }, |
|
45 |
|
46 { keyPath: ["foo", "bar"], value: { foo: 1, bar: 2 }, key: [1, 2] }, |
|
47 { keyPath: ["foo"], value: { foo: 1, bar: 2 }, key: [1] }, |
|
48 { keyPath: ["foo", "bar", "bar"], value: { foo: 1, bar: "x" }, key: [1, "x", "x"] }, |
|
49 { keyPath: ["x", "y"], value: { x: [], y: "x" }, key: [[], "x"] }, |
|
50 { keyPath: ["x", "y"], value: { x: [[1]], y: "x" }, key: [[[1]], "x"] }, |
|
51 { keyPath: ["x", "y"], value: { x: [[1]], y: new Date(1) }, key: [[[1]], new Date(1)] }, |
|
52 { keyPath: ["x", "y"], value: { x: [[1]], y: [new Date(3)] }, key: [[[1]], [new Date(3)]] }, |
|
53 { keyPath: ["x", "y.bar"], value: { x: "hi", y: { bar: "x"} }, key: ["hi", "x"] }, |
|
54 { keyPath: ["x.y", "y.bar"], value: { x: { y: "hello" }, y: { bar: "nurse"} }, key: ["hello", "nurse"] }, |
|
55 { keyPath: ["", ""], value: 5, key: [5, 5] }, |
|
56 { keyPath: ["x", "y"], value: { x: 1 } }, |
|
57 { keyPath: ["x", "y"], value: { y: 1 } }, |
|
58 { keyPath: ["x", "y"], value: { x: 1, y: undefined } }, |
|
59 { keyPath: ["x", "y"], value: { x: null, y: 1 } }, |
|
60 { keyPath: ["x", "y.bar"], value: { x: null, y: { bar: "x"} } }, |
|
61 { keyPath: ["x", "y"], value: { x: 1, y: false } }, |
|
62 { keyPath: ["x", "y", "z"], value: { x: 1, y: false, z: "a" } }, |
|
63 { keyPath: [".x", "y", "z"], exception: true }, |
|
64 { keyPath: ["x", "y ", "z"], exception: true }, |
|
65 ]; |
|
66 |
|
67 let openRequest = indexedDB.open(name, 1); |
|
68 openRequest.onerror = errorHandler; |
|
69 openRequest.onupgradeneeded = grabEventAndContinueHandler; |
|
70 openRequest.onsuccess = unexpectedSuccessHandler; |
|
71 let event = yield undefined; |
|
72 let db = event.target.result; |
|
73 |
|
74 let stores = {}; |
|
75 |
|
76 // Test creating object stores and inserting data |
|
77 for (let i = 0; i < keyPaths.length; i++) { |
|
78 let info = keyPaths[i]; |
|
79 |
|
80 let test = " for objectStore test " + JSON.stringify(info); |
|
81 let indexName = JSON.stringify(info.keyPath); |
|
82 if (!stores[indexName]) { |
|
83 try { |
|
84 let objectStore = db.createObjectStore(indexName, { keyPath: info.keyPath }); |
|
85 ok(!("exception" in info), "shouldn't throw" + test); |
|
86 is(JSON.stringify(objectStore.keyPath), JSON.stringify(info.keyPath), |
|
87 "correct keyPath property" + test); |
|
88 ok(objectStore.keyPath === objectStore.keyPath, |
|
89 "object identity should be preserved"); |
|
90 stores[indexName] = objectStore; |
|
91 } catch (e) { |
|
92 ok("exception" in info, "should throw" + test); |
|
93 is(e.name, "SyntaxError", "expect a SyntaxError" + test); |
|
94 ok(e instanceof DOMException, "Got a DOM Exception" + test); |
|
95 is(e.code, DOMException.SYNTAX_ERR, "expect a syntax error" + test); |
|
96 continue; |
|
97 } |
|
98 } |
|
99 |
|
100 let store = stores[indexName]; |
|
101 |
|
102 try { |
|
103 request = store.add(info.value); |
|
104 ok("key" in info, "successfully created request to insert value" + test); |
|
105 } catch (e) { |
|
106 ok(!("key" in info), "threw when attempted to insert" + test); |
|
107 ok(e instanceof DOMException, "Got a DOMException" + test); |
|
108 is(e.name, "DataError", "expect a DataError" + test); |
|
109 is(e.code, 0, "expect zero" + test); |
|
110 continue; |
|
111 } |
|
112 |
|
113 request.onerror = errorHandler; |
|
114 request.onsuccess = grabEventAndContinueHandler; |
|
115 |
|
116 let e = yield undefined; |
|
117 is(e.type, "success", "inserted successfully" + test); |
|
118 is(e.target, request, "expected target" + test); |
|
119 ok(compareKeys(request.result, info.key), "found correct key" + test); |
|
120 is(indexedDB.cmp(request.result, info.key), 0, "returned key compares correctly" + test); |
|
121 |
|
122 store.get(info.key).onsuccess = grabEventAndContinueHandler; |
|
123 e = yield undefined; |
|
124 isnot(e.target.result, undefined, "Did find entry"); |
|
125 |
|
126 // Check that cursor.update work as expected |
|
127 request = store.openCursor(); |
|
128 request.onerror = errorHandler; |
|
129 request.onsuccess = grabEventAndContinueHandler; |
|
130 e = yield undefined; |
|
131 let cursor = e.target.result; |
|
132 request = cursor.update(info.value); |
|
133 request.onerror = errorHandler; |
|
134 request.onsuccess = grabEventAndContinueHandler; |
|
135 yield undefined; |
|
136 ok(true, "Successfully updated cursor" + test); |
|
137 |
|
138 // Check that cursor.update throws as expected when key is changed |
|
139 let newValue = cursor.value; |
|
140 let destProp = Array.isArray(info.keyPath) ? info.keyPath[0] : info.keyPath; |
|
141 if (destProp) { |
|
142 eval("newValue." + destProp + " = 'newKeyValue'"); |
|
143 } |
|
144 else { |
|
145 newValue = 'newKeyValue'; |
|
146 } |
|
147 let didThrow; |
|
148 try { |
|
149 cursor.update(newValue); |
|
150 } |
|
151 catch (ex) { |
|
152 didThrow = ex; |
|
153 } |
|
154 ok(didThrow instanceof DOMException, "Got a DOMException" + test); |
|
155 is(didThrow.name, "DataError", "expect a DataError" + test); |
|
156 is(didThrow.code, 0, "expect zero" + test); |
|
157 |
|
158 // Clear object store to prepare for next test |
|
159 store.clear().onsuccess = grabEventAndContinueHandler; |
|
160 yield undefined; |
|
161 } |
|
162 |
|
163 // Attempt to create indexes and insert data |
|
164 let store = db.createObjectStore("indexStore"); |
|
165 let indexes = {}; |
|
166 for (let i = 0; i < keyPaths.length; i++) { |
|
167 let test = " for index test " + JSON.stringify(info); |
|
168 let info = keyPaths[i]; |
|
169 let indexName = JSON.stringify(info.keyPath); |
|
170 if (!indexes[indexName]) { |
|
171 try { |
|
172 let index = store.createIndex(indexName, info.keyPath); |
|
173 ok(!("exception" in info), "shouldn't throw" + test); |
|
174 is(JSON.stringify(index.keyPath), JSON.stringify(info.keyPath), |
|
175 "index has correct keyPath property" + test); |
|
176 ok(index.keyPath === index.keyPath, |
|
177 "object identity should be preserved"); |
|
178 indexes[indexName] = index; |
|
179 } catch (e) { |
|
180 ok("exception" in info, "should throw" + test); |
|
181 is(e.name, "SyntaxError", "expect a SyntaxError" + test); |
|
182 ok(e instanceof DOMException, "Got a DOM Exception" + test); |
|
183 is(e.code, DOMException.SYNTAX_ERR, "expect a syntax error" + test); |
|
184 continue; |
|
185 } |
|
186 } |
|
187 |
|
188 let index = indexes[indexName]; |
|
189 |
|
190 request = store.add(info.value, 1); |
|
191 if ("key" in info) { |
|
192 index.getKey(info.key).onsuccess = grabEventAndContinueHandler; |
|
193 e = yield undefined; |
|
194 is(e.target.result, 1, "found value when reading" + test); |
|
195 } |
|
196 else { |
|
197 index.count().onsuccess = grabEventAndContinueHandler; |
|
198 e = yield undefined; |
|
199 is(e.target.result, 0, "should be empty" + test); |
|
200 } |
|
201 |
|
202 store.clear().onsuccess = grabEventAndContinueHandler; |
|
203 yield undefined; |
|
204 } |
|
205 |
|
206 // Autoincrement and complex key paths |
|
207 let aitests = [{ v: {}, k: 1, res: { foo: { id: 1 }} }, |
|
208 { v: { value: "x" }, k: 2, res: { value: "x", foo: { id: 2 }} }, |
|
209 { v: { value: "x", foo: {} }, k: 3, res: { value: "x", foo: { id: 3 }} }, |
|
210 { v: { v: "x", foo: { x: "y" } }, k: 4, res: { v: "x", foo: { x: "y", id: 4 }} }, |
|
211 { v: { value: 2, foo: { id: 10 }}, k: 10 }, |
|
212 { v: { value: 2 }, k: 11, res: { value: 2, foo: { id: 11 }} }, |
|
213 { v: true, }, |
|
214 { v: { value: 2, foo: 12 }, }, |
|
215 { v: { foo: { id: true }}, }, |
|
216 { v: { foo: { x: 5, id: {} }}, }, |
|
217 { v: undefined, }, |
|
218 { v: { foo: undefined }, }, |
|
219 { v: { foo: { id: undefined }}, }, |
|
220 { v: null, }, |
|
221 { v: { foo: null }, }, |
|
222 { v: { foo: { id: null }}, }, |
|
223 ]; |
|
224 |
|
225 store = db.createObjectStore("gen", { keyPath: "foo.id", autoIncrement: true }); |
|
226 for (let i = 0; i < aitests.length; ++i) { |
|
227 let info = aitests[i]; |
|
228 let test = " for autoIncrement test " + JSON.stringify(info); |
|
229 |
|
230 let preValue = JSON.stringify(info.v); |
|
231 if ("k" in info) { |
|
232 store.add(info.v).onsuccess = grabEventAndContinueHandler; |
|
233 is(JSON.stringify(info.v), preValue, "put didn't modify value" + test); |
|
234 } |
|
235 else { |
|
236 try { |
|
237 store.add(info.v); |
|
238 ok(false, "should throw" + test); |
|
239 } |
|
240 catch(e) { |
|
241 ok(true, "did throw" + test); |
|
242 ok(e instanceof DOMException, "Got a DOMException" + test); |
|
243 is(e.name, "DataError", "expect a DataError" + test); |
|
244 is(e.code, 0, "expect zero" + test); |
|
245 |
|
246 is(JSON.stringify(info.v), preValue, "failing put didn't modify value" + test); |
|
247 |
|
248 continue; |
|
249 } |
|
250 } |
|
251 |
|
252 let e = yield undefined; |
|
253 is(e.target.result, info.k, "got correct return key" + test); |
|
254 |
|
255 store.get(info.k).onsuccess = grabEventAndContinueHandler; |
|
256 e = yield undefined; |
|
257 is(JSON.stringify(e.target.result), JSON.stringify(info.res || info.v), |
|
258 "expected value stored" + test); |
|
259 } |
|
260 |
|
261 openRequest.onsuccess = grabEventAndContinueHandler; |
|
262 yield undefined; |
|
263 |
|
264 finishTest(); |
|
265 yield undefined; |
|
266 } |