1 | 'use strict'
|
2 |
|
3 | const sinon = require('sinon')
|
4 | const index = require('../index')
|
5 | const memory = require('../adaptors/in-memory')
|
6 | const local = require('../repositories/local')
|
7 | const remote = require('../repositories/remote')
|
8 | const ConflictError = require('../errors/conflict')
|
9 | const MigrationUpError = require('../errors/migration-up')
|
10 | const MigrationDownError = require('../errors/migration-down')
|
11 |
|
12 | describe('mygreat', () => {
|
13 | describe('.from(localAdaptor Object, remoteAdaptor Object): Object', () => {
|
14 | it('creates an instance of mygreat using built-in repositories', () => {
|
15 | const mygreat = index.from(memory([]), memory([]))
|
16 |
|
17 | expect( mygreat ).to.have.property('up')
|
18 | expect( mygreat ).to.have.property('down')
|
19 | })
|
20 | })
|
21 | })
|
22 |
|
23 | describe('mygreat(localRepository Object, remoteRepository Object): Object', () => {
|
24 | const localAdaptor = memory([
|
25 | {
|
26 | name: '20170914202400',
|
27 | content: {
|
28 | up: (spies) => { spies['20170914202400'].up() },
|
29 | down: (spies) => { spies['20170914202400'].down() }
|
30 | }
|
31 | },
|
32 | {
|
33 | name: '20170914210100',
|
34 | content: {
|
35 | up: (spies) => { spies['20170914210100'].up() },
|
36 | down: (spies) => { spies['20170914210100'].down() }
|
37 | }
|
38 | },
|
39 | {
|
40 | name: '20170914210300',
|
41 | content: {
|
42 | up: (spies) => { spies['20170914210300'].up() },
|
43 | down: (spies) => { spies['20170914210300'].down() }
|
44 | }
|
45 | }
|
46 | ])
|
47 |
|
48 | describe('.up(...args): Promise<Object>', () => {
|
49 | const mygreatConflict = index(local(localAdaptor), remote(memory([{
|
50 | name: '832185ad-1041-2343-2342-2a80a7c23c4b',
|
51 | content: [
|
52 | '20170914210300'
|
53 | ]
|
54 | }])))
|
55 |
|
56 | it('fails if there are any conflictable-unsynced migrations', () => {
|
57 | return expect( mygreatConflict.up(null) )
|
58 | .to.eventually.be.rejectedWith(ConflictError)
|
59 | })
|
60 |
|
61 | it('the error thrown in case of conflicts carries the array of conflicts', () => {
|
62 | return expect( mygreatConflict.up(null).catch(err => err.conflicts) )
|
63 | .to.eventually.be.an('array')
|
64 | })
|
65 |
|
66 | it('returns a migration registry', () => {
|
67 | const mygreat = index(local(memory([])), remote(memory([])))
|
68 | return expect( mygreat.up({}) ).to.eventually.have.property('content')
|
69 | })
|
70 |
|
71 | it('passes a given set of arguments to all unsynced migrations', () => {
|
72 | const mygreat = index(local(localAdaptor), remote(memory([{
|
73 | name: '832185ad-1041-2343-2342-2a80a7c23c4b',
|
74 | content: [
|
75 | '20170914202400',
|
76 | ]
|
77 | }])))
|
78 |
|
79 | const arg = {
|
80 | '20170914202400': { up: sinon.spy(), down: sinon.spy() },
|
81 | '20170914210100': { up: sinon.spy(), down: sinon.spy() },
|
82 | '20170914210300': { up: sinon.spy(), down: sinon.spy() },
|
83 | }
|
84 |
|
85 | return expect(
|
86 | mygreat.up(arg)
|
87 | .then(() => Object.values(arg).map(m => ({
|
88 | up: m.up.calledOnce,
|
89 | down: m.down.calledOnce
|
90 | })))
|
91 | ).to.eventually.be.deep.equals([
|
92 | { up: false, down: false },
|
93 | { up: true, down: false },
|
94 | { up: true, down: false }
|
95 | ])
|
96 | })
|
97 |
|
98 | it('none migrations are executed if everything is synced', () => {
|
99 | const mygreat = index(local(localAdaptor), remote(memory([{
|
100 | name: '832185ad-1041-2343-2342-2a80a7c23c4b',
|
101 | content: [
|
102 | '20170914202400',
|
103 | '20170914210100',
|
104 | '20170914210300'
|
105 | ]
|
106 | }])))
|
107 |
|
108 | const arg = {
|
109 | '20170914202400': { up: sinon.spy(), down: sinon.spy() },
|
110 | '20170914210100': { up: sinon.spy(), down: sinon.spy() },
|
111 | '20170914210300': { up: sinon.spy(), down: sinon.spy() },
|
112 | }
|
113 |
|
114 | return expect(
|
115 | mygreat.up(arg)
|
116 | .then(() => Object.values(arg).map(m => ({
|
117 | up: m.up.calledOnce,
|
118 | down: m.down.calledOnce
|
119 | })))
|
120 | ).to.eventually.be.deep.equals([
|
121 | { up: false, down: false },
|
122 | { up: false, down: false },
|
123 | { up: false, down: false }
|
124 | ])
|
125 | })
|
126 |
|
127 | it('creates a new registry on remote repository on success, if at least one migration file has ran', () => {
|
128 | const adaptor = memory([{
|
129 | name: '832185ad-1041-2343-2342-2a80a7c23c4b',
|
130 | content: [
|
131 | '20170914202400',
|
132 | ]
|
133 | }])
|
134 |
|
135 | const mygreat = index(local(localAdaptor), remote(adaptor))
|
136 |
|
137 | const arg = {
|
138 | '20170914202400': { up: sinon.spy(), down: sinon.spy() },
|
139 | '20170914210100': { up: sinon.spy(), down: sinon.spy() },
|
140 | '20170914210300': { up: sinon.spy(), down: sinon.spy() },
|
141 | }
|
142 |
|
143 | return expect(
|
144 | mygreat.up(arg)
|
145 | .then(() => adaptor.all())
|
146 | .then(all => all.length)
|
147 | ).to.eventually.be.equals(2)
|
148 | })
|
149 |
|
150 | it('creates none new registry on remote repository on success when none migration files ran', () => {
|
151 | const adaptor = memory([{
|
152 | name: '832185ad-1041-2343-2342-2a80a7c23c4b',
|
153 | content: [
|
154 | '20170914202400',
|
155 | '20170914210100',
|
156 | '20170914210300'
|
157 | ]
|
158 | }])
|
159 |
|
160 | const mygreat = index(local(localAdaptor), remote(adaptor))
|
161 |
|
162 | const arg = {
|
163 | '20170914202400': { up: sinon.spy(), down: sinon.spy() },
|
164 | '20170914210100': { up: sinon.spy(), down: sinon.spy() },
|
165 | '20170914210300': { up: sinon.spy(), down: sinon.spy() },
|
166 | }
|
167 |
|
168 | return expect(
|
169 | mygreat.up(arg)
|
170 | .then(() => adaptor.all())
|
171 | .then(all => all.length)
|
172 | ).to.eventually.be.equals(1)
|
173 | })
|
174 |
|
175 | it('throw a MigrationException if an exception is thrown during the execution', () => {
|
176 | const crachable = index(local(memory([{
|
177 | name: '20170914210300',
|
178 | content: {
|
179 | up: async (instance) => { throw Error('expected error') },
|
180 | down: async (instance) => { }
|
181 | }
|
182 | }])), remote(memory([])))
|
183 |
|
184 | return expect( crachable.up({}) )
|
185 | .to.eventually.be.rejectedWith(MigrationUpError)
|
186 | })
|
187 |
|
188 | it('thrown MigrationException carries the migrationRegistry', () => {
|
189 | const crachable = index(local(memory([{
|
190 | name: '20170914210300',
|
191 | content: {
|
192 | up: async (instance) => { throw Error('expected error') },
|
193 | down: async (instance) => { }
|
194 | }
|
195 | }])), remote(memory([])))
|
196 |
|
197 | return expect( crachable.up({}).catch(err => err.migrationRegistry) )
|
198 | .to.eventually.be.shallowDeepEqual({ content: [] })
|
199 | })
|
200 | })
|
201 |
|
202 | describe('.down(...args): Promise<Object>', () => {
|
203 | it('takes the latest migration registry\'s files and pass the given arguments to their down methods', () => {
|
204 | const mygreat = index(local(memory([
|
205 | { name: '20170914202400', content: { down: async (spies) => spies['20170914202400'].down() } },
|
206 | { name: '20170914210100', content: { down: async (spies) => spies['20170914210100'].down() } },
|
207 | ])), remote(memory([{
|
208 | name: '832185ad-1041-2343-2342-2a80a7c23c4b',
|
209 | content: [
|
210 | '20170914202400',
|
211 | '20170914210100'
|
212 | ]
|
213 | }])))
|
214 |
|
215 | const arg = {
|
216 | '20170914202400': { up: sinon.spy(), down: sinon.spy() },
|
217 | '20170914210100': { up: sinon.spy(), down: sinon.spy() }
|
218 | }
|
219 |
|
220 | return expect(
|
221 | mygreat.down(arg)
|
222 | .then(() => Object.values(arg).map(m => ({
|
223 | up: m.up.called,
|
224 | down: m.down.called
|
225 | })))
|
226 | ).to.eventually.be.deep.equals([
|
227 | { up: false, down: true },
|
228 | { up: false, down: true }
|
229 | ])
|
230 | })
|
231 |
|
232 | it('removes the migration registry after the execution', () => {
|
233 | const remoteAdaptor = memory([{
|
234 | name: '832185ad-1041-2343-2342-2a80a7c23c4b',
|
235 | content: [
|
236 | '20170914202400',
|
237 | '20170914210100'
|
238 | ]
|
239 | }])
|
240 |
|
241 | const mygreat = index(local(memory([
|
242 | { name: '20170914202400', content: { down: async () => { } } },
|
243 | { name: '20170914210100', content: { down: async () => { } } },
|
244 | ])), remote(remoteAdaptor))
|
245 |
|
246 | return expect(
|
247 | mygreat.down(null)
|
248 | .then(() => remoteAdaptor.all())
|
249 | ).to.eventually.be.deep.equals([])
|
250 | })
|
251 | })
|
252 | })
|