summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/IndexedDB/upgrade-transaction-lifecycle-user-aborted.html
blob: 4094ce34f34aa06d8ce4433b963819cf4f39f6b6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
<!doctype html>
<meta charset="utf8">
<title>IndexedDB: user-abort()ed versionchange transaction lifecycle</title>
<link rel="help"
      href="https://w3c.github.io/IndexedDB/#upgrade-transaction-steps">
<link rel="help"
      href="https://w3c.github.io/IndexedDB/#dom-idbdatabase-createobjectstore">
<link rel="help"
      href="https://w3c.github.io/IndexedDB/#dom-idbdatabase-deleteobjectstore">
<link rel="author" href="pwnall@chromium.org" title="Victor Costan">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="resources/support-promises.js"></script>
<script>
'use strict';

promise_test(t => {
  return createDatabase(t, database => {
    createBooksStore(t, database);
  }).then(database => {
    database.close();
  }).then(() => migrateDatabase(t, 2, (database, transaction, request) => {
    transaction.abort();
    assert_equals(
        request.transaction, transaction,
        "The open request's transaction should be reset after onabort");

    assert_throws_dom(
        'TransactionInactiveError',
        () => { database.createObjectStore('books2'); },
        'createObjectStore exception should reflect that the transaction is ' +
        'still running');
    assert_throws_dom(
        'TransactionInactiveError',
        () => { database.deleteObjectStore('books'); },
        'deleteObjectStore exception should reflect that the transaction is' +
        'still running');
  }));
}, 'synchronously after abort() is called');

promise_test(t => {
  return createDatabase(t, database => {
    createBooksStore(t, database);
  }).then(database => {
    database.close();
  }).then(() => migrateDatabase(t, 2, (database, transaction, request) => {
    let abortFired = false;
    const abortPromise = new Promise((resolve, reject) => {
      transaction.addEventListener('abort', () => {
        abortFired = true;
        resolve();
      }, false);
      transaction.abort();
    });

    return Promise.resolve().then(() => {
      assert_false(
          abortFired,
          'The abort event should fire after promises are resolved');
      assert_equals(
          request.transaction, transaction,
          "The open request's transaction should be reset after onabort");
      assert_throws_dom(
          'TransactionInactiveError',
          () => { database.createObjectStore('books2'); },
          'createObjectStore exception should reflect that the transaction ' +
          'is still running');
      assert_throws_dom(
          'TransactionInactiveError',
          () => { database.deleteObjectStore('books'); },
          'deleteObjectStore exception should reflect that the transaction ' +
          'is still running');
    }).then(() => abortPromise);
  }));
}, 'in a promise microtask after abort() is called, before the transaction ' +
   'abort event is fired');

promise_test(t => {
  return createDatabase(t, database => {
    createBooksStore(t, database);
  }).then(database => {
    database.close();
  }).then(() => migrateDatabase(t, 2, (database, transaction, request) => {
    return new Promise((resolve, reject) => {
      transaction.addEventListener('abort', () => {
        resolve(new Promise((resolve, reject) => {
          assert_equals(
              request.transaction, transaction,
              "The open request's transaction should be reset after onabort");
          assert_throws_dom(
              'InvalidStateError',
              () => { database.createObjectStore('books2'); },
              'createObjectStore exception should reflect that the ' +
              'transaction is no longer running');
          assert_throws_dom(
              'InvalidStateError',
              () => { database.deleteObjectStore('books'); },
              'deleteObjectStore exception should reflect that the ' +
              'transaction is no longer running');
          resolve();
        }));
      }, false);
      transaction.abort();
    });
  }));
}, 'in the abort event handler for a transaction aborted due to an abort() ' +
   'call');

promise_test(t => {
  return createDatabase(t, database => {
    createBooksStore(t, database);
  }).then(database => {
    database.close();
  }).then(() => migrateDatabase(t, 2, (database, transaction, request) => {
    return new Promise((resolve, reject) => {
      transaction.addEventListener('abort', () => {
        setTimeout(() => {
          resolve(new Promise((resolve, reject) => {
            assert_equals(
                request.transaction, null,
                "The open request's transaction should be reset after " +
                'onabort microtasks');
            assert_throws_dom(
                'InvalidStateError',
                () => { database.createObjectStore('books2'); },
                'createObjectStore exception should reflect that the ' +
                'transaction is no longer running');
            assert_throws_dom(
                'InvalidStateError',
                () => { database.deleteObjectStore('books'); },
                'deleteObjectStore exception should reflect that the ' +
                'transaction is no longer running');
            resolve();
          }));
        }, 0);
      }, false);
      transaction.abort();
    });
  }));
}, 'in a setTimeout(0) callback after the abort event is fired for a ' +
   'transaction aborted due to an abort() call');

</script>