- 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
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 242
- 243
- 244
- 245
- 246
- 247
- 248
- 249
- 250
- 251
- 252
- 253
- 254
- 255
- 256
- 257
- 258
- 259
- 260
- 261
- 262
- 263
- 264
- 265
- 266
- 267
- 268
- 269
- 270
- 271
- 272
- 273
- 274
- 275
- 276
- 277
- 278
- 279
- 280
- 281
- 282
- 283
- 284
- 285
- 286
- 287
- 288
- 289
- 290
- 291
- 292
- 293
- 294
- 295
- 296
- 297
- 298
- 299
- 300
- 301
- 302
- 303
- 304
- 305
- 306
- 307
- 308
- 309
- 310
- 311
- 312
- 313
- 314
- 315
- 316
- 317
- 318
- 319
- 320
- 321
- 322
- 323
- 324
- 325
- 326
- 327
- 328
- 329
- 330
- 331
- 332
- 333
- 334
- 335
- 336
- 337
- 338
- 339
- 340
- 341
- 342
- 343
- 344
- 345
- 346
- 347
- 348
- 349
- 350
- 351
- 352
- 353
- 354
- 355
- 356
- 357
- 358
- 359
- 360
- 361
- 362
- 363
- 364
- 365
- 366
- 367
- 368
- 369
- 370
- 371
- 372
- 373
- 374
- 375
- 376
- 377
- 378
- 379
- 380
- 381
- 382
- 383
- 384
- 385
- 386
- 387
- 388
- 389
- 390
- 391
- 392
- 393
- 394
- 395
- 396
- 397
- 398
- 399
- 400
- 401
- 402
- 403
import path from 'path';
import type { IAddOptions } from '@pixi/loaders';
import { Loader, LoaderResource } from '@pixi/loaders';
import { Texture, BaseTexture, extensions } from '@pixi/core';
import { BaseTextureCache, TextureCache, url, clearTextureCache } from '@pixi/utils';
import { SpritesheetLoader, Spritesheet } from '@pixi/spritesheet';
describe('SpritesheetLoader', () =>
{
beforeAll(() => extensions.add(SpritesheetLoader));
afterAll(() => extensions.remove(SpritesheetLoader));
it('should exist and return a function', () =>
{
expect(SpritesheetLoader).toBeDefined();
expect(SpritesheetLoader.use).toBeInstanceOf(Function);
});
it('should install middleware', (done) =>
{
const loader = new Loader();
const baseTextures = Object.keys(BaseTextureCache).length;
const textures = Object.keys(TextureCache).length;
loader.add('building1', path.join(__dirname, 'resources/building1.json'));
loader.load((loader, resources) =>
{
expect(resources.building1).toBeInstanceOf(LoaderResource);
expect(resources.building1.spritesheet).toBeInstanceOf(Spritesheet);
resources.building1.spritesheet.destroy(true);
expect(Object.keys(BaseTextureCache).length).toEqual(baseTextures);
expect(Object.keys(TextureCache).length).toEqual(textures);
loader.reset();
done();
});
});
it('should do nothing if the resource is not JSON', () =>
{
const spy = jest.fn();
const res = {} as LoaderResource;
SpritesheetLoader.use(res, spy);
expect(spy).toHaveBeenCalledOnce();
expect(res.textures).toBeUndefined();
});
it('should do nothing if the resource is JSON, but improper format', () =>
{
const spy = jest.fn();
const res = createMockResource(LoaderResource.TYPE.JSON, {});
SpritesheetLoader.use(res, spy);
expect(spy).toHaveBeenCalledOnce();
expect(res.textures).toBeUndefined();
});
it('should load the image & create textures if json is properly formatted', async () =>
{
jest.setTimeout(10000);
const res = createMockResource(LoaderResource.TYPE.JSON, getJsonSpritesheet());
const loader = new Loader();
const imgRes = createMockResource(LoaderResource.TYPE.IMAGE, new Image());
const addStub = jest.fn((_0, _1, _2, callback) =>
{
callback(imgRes);
});
loader.add = addStub as any;
imgRes.texture = new Texture(new BaseTexture(imgRes.data));
await new Promise<void>((resolve) =>
{
SpritesheetLoader.use.call(loader, res, () =>
{
resolve();
});
});
expect(res).toHaveProperty('textures');
expect(Object.keys(res.textures)).toEqual(Object.keys(getJsonSpritesheet().frames));
expect(res.textures['0.png']).toBeInstanceOf(Texture);
expect(res.textures['0.png'].frame.x).toEqual(14);
expect(res.textures['0.png'].frame.y).toEqual(28);
expect(res.textures['0.png'].defaultAnchor.x).toEqual(0.3);
expect(res.textures['0.png'].defaultAnchor.y).toEqual(0.4);
expect(res.textures['1.png'].defaultAnchor.x).toEqual(0.0); // default of defaultAnchor is 0,0
expect(res.textures['1.png'].defaultAnchor.y).toEqual(0.0);
expect(res).toHaveProperty('spritesheet');
expect(res.spritesheet).toHaveProperty('animations');
expect(res.spritesheet.animations).toHaveProperty('png123');
expect(res.spritesheet.animations.png123.length).toEqual(3);
expect(res.spritesheet.animations.png123[0]).toEqual(res.textures['1.png']);
});
it('should not load binary images as an image loader type', (done) =>
{
const loader = new Loader();
// provide a mock pre-loader that creates an empty base texture for compressed texture assets
// this is necessary because the SpriteSheetLoader expects a baseTexture on the resource
loader.pre((resource, next) =>
{
if (resource.extension === 'crn')
{
resource.texture = Texture.EMPTY;
}
next();
})
.add(`atlas_crn`, path.join(__dirname, 'resources', 'atlas_crn.json'))
.add(`atlas`, path.join(__dirname, 'resources', 'building1.json'))
.load((loader, resources) =>
{
expect(resources.atlas_image.data).toBeInstanceOf(HTMLImageElement);
expect(resources.atlas_crn_image.data).not.toBeInstanceOf(HTMLImageElement);
loader.reset();
done();
});
});
it('should dispatch an error failing to load spritesheet image', (done) =>
{
const spy = jest.fn((error, _ldr, res) =>
{
expect(res.name).toEqual('atlas_error_image');
expect(res.error).toEqual(error);
expect(error.toString()).toContain('Failed to load element using: IMG');
});
const loader = new Loader();
loader.add('atlas_error', path.join(__dirname, 'resources', 'atlas_error.json'));
loader.onError.add(spy);
loader.load((loader, resources) =>
{
expect(resources.atlas_error_image.error).toBeInstanceOf(Error);
expect(spy).toBeCalledTimes(1);
loader.reset();
done();
});
});
it('should build the image url', () =>
{
function getPath(url: string, image: string)
{
return SpritesheetLoader.getResourcePath(
{
url,
data: { meta: { image } },
} as LoaderResource,
''
);
}
let result = getPath('http://some.com/spritesheet.json', 'img.png');
expect(result).toEqual('http://some.com/img.png');
result = getPath('http://some.com/some/dir/spritesheet.json', 'img.png');
expect(result).toEqual('http://some.com/some/dir/img.png');
result = getPath('http://some.com/some/dir/spritesheet.json', './img.png');
expect(result).toEqual('http://some.com/some/dir/img.png');
result = getPath('http://some.com/some/dir/spritesheet.json', '../img.png');
expect(result).toEqual('http://some.com/some/img.png');
result = getPath('/spritesheet.json', 'img.png');
expect(result).toEqual('/img.png');
result = getPath('/some/dir/spritesheet.json', 'img.png');
expect(result).toEqual('/some/dir/img.png');
result = getPath('/some/dir/spritesheet.json', './img.png');
expect(result).toEqual('/some/dir/img.png');
result = getPath('/some/dir/spritesheet.json', '../img.png');
expect(result).toEqual('/some/img.png');
});
// TODO: Test that rectangles are created correctly.
// TODO: Test that bathc processing works correctly.
// TODO: Test that resolution processing works correctly.
// TODO: Test that metadata is honored.
it('should not add itself via multipack', (done) =>
{
// clear the caches only to avoid cluttering the output
clearTextureCache();
const loader = new Loader();
loader.add('atlas_multi_self', path.join(__dirname, 'resources', 'building1-0.json'));
loader.load((loader, resources) =>
{
expect(Object.values(resources).filter((r) => r.url.includes('building1-0.json')).length).toEqual(1);
loader.reset();
done();
});
});
it('should create multipack resources when related_multi_packs field is an array of strings', (done) =>
{
// clear the caches only to avoid cluttering the output
clearTextureCache();
const loader = new Loader();
loader.add('atlas_multi_child_check', path.join(__dirname, 'resources', 'building1-0.json'));
loader.load((loader, resources) =>
{
expect(resources.atlas_multi_child_check.children.some((r) => r.url.includes('building1-1.json'))).toBe(true);
loader.reset();
done();
});
});
it('should not create multipack resources when related_multi_packs field is missing or the wrong type', (done) =>
{
// clear the caches only to avoid cluttering the output
clearTextureCache();
const loader = new Loader();
loader.add('atlas_no_multipack', path.join(__dirname, 'resources', 'building1.json'));
loader.add('atlas_multipack_wrong_type', path.join(__dirname, 'resources', 'atlas-multipack-wrong-type.json'));
loader.add('atlas_multipack_wrong_array', path.join(__dirname, 'resources', 'atlas-multipack-wrong-array.json'));
loader.load((loader, resources) =>
{
expect(resources.atlas_no_multipack.children.length).toEqual(1);
expect(resources.atlas_multipack_wrong_type.children.length).toEqual(1);
expect(resources.atlas_multipack_wrong_array.children.length).toEqual(1);
loader.reset();
done();
});
});
it('should build the multipack url', () =>
{
let result = url.resolve('http://some.com/spritesheet.json', 'spritesheet-1.json');
expect(result).toEqual('http://some.com/spritesheet-1.json');
result = url.resolve('http://some.com/some/dir/spritesheet.json', 'spritesheet-1.json');
expect(result).toEqual('http://some.com/some/dir/spritesheet-1.json');
result = url.resolve('http://some.com/some/dir/spritesheet.json', './spritesheet-1.json');
expect(result).toEqual('http://some.com/some/dir/spritesheet-1.json');
result = url.resolve('http://some.com/some/dir/spritesheet.json', '../spritesheet-1.json');
expect(result).toEqual('http://some.com/some/spritesheet-1.json');
result = url.resolve('/spritesheet.json', 'spritesheet-1.json');
expect(result).toEqual('/spritesheet-1.json');
result = url.resolve('/some/dir/spritesheet.json', 'spritesheet-1.json');
expect(result).toEqual('/some/dir/spritesheet-1.json');
result = url.resolve('/some/dir/spritesheet.json', './spritesheet-1.json');
expect(result).toEqual('/some/dir/spritesheet-1.json');
result = url.resolve('/some/dir/spritesheet.json', '../spritesheet-1.json');
expect(result).toEqual('/some/spritesheet-1.json');
});
it('should use metadata to load all multipack resources', (done) =>
{
// clear the caches only to avoid cluttering the output
clearTextureCache();
const loader = new Loader();
const metadata = { key: 'value' };
loader.add('building1-0', path.join(__dirname, 'resources', 'building1-0.json'), { metadata } as IAddOptions);
loader.load((_loader, resources) =>
{
expect(resources['building1-0'].metadata).toEqual(metadata);
expect(resources['building1-1'].metadata).toEqual(metadata);
done();
});
});
});
function createMockResource(type: LoaderResource.TYPE, data: any): LoaderResource
{
const name = `${Math.floor(Date.now() * Math.random())}`;
return {
url: `http://localhost/doesnt_exist/${name}`,
name,
type,
data,
metadata: {},
} as LoaderResource;
}
function getJsonSpritesheet()
{
/* eslint-disable */
return {"frames": {
"0.png":
{
"frame": {"x":14,"y":28,"w":14,"h":14},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":14,"h":14},
"sourceSize": {"w":14,"h":14},
"anchor": {"x":0.3,"y":0.4}
},
"1.png":
{
"frame": {"x":14,"y":42,"w":12,"h":14},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":14},
"sourceSize": {"w":12,"h":14}
},
"2.png":
{
"frame": {"x":14,"y":14,"w":14,"h":14},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":14,"h":14},
"sourceSize": {"w":14,"h":14}
},
"3.png":
{
"frame": {"x":42,"y":0,"w":14,"h":14},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":14,"h":14},
"sourceSize": {"w":14,"h":14}
},
"4.png":
{
"frame": {"x":28,"y":0,"w":14,"h":14},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":14,"h":14},
"sourceSize": {"w":14,"h":14}
},
"5.png":
{
"frame": {"x":14,"y":0,"w":14,"h":14},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":14,"h":14},
"sourceSize": {"w":14,"h":14}
},
"6.png":
{
"frame": {"x":0,"y":42,"w":14,"h":14},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":14,"h":14},
"sourceSize": {"w":14,"h":14}
},
"7.png":
{
"frame": {"x":0,"y":28,"w":14,"h":14},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":14,"h":14},
"sourceSize": {"w":14,"h":14}
},
"8.png":
{
"frame": {"x":0,"y":14,"w":14,"h":14},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":14,"h":14},
"sourceSize": {"w":14,"h":14}
},
"9.png":
{
"frame": {"x":0,"y":0,"w":14,"h":14},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":14,"h":14},
"sourceSize": {"w":14,"h":14}
}},
"animations": {
"png123": [ "1.png", "2.png", "3.png" ]
},
"meta": {
"app": "http://www.texturepacker.com",
"version": "1.0",
"image": "hud.png",
"format": "RGBA8888",
"size": {"w":64,"h":64},
"scale": "1",
"smartupdate": "$TexturePacker:SmartUpdate:47025c98c8b10634b75172d4ed7e7edc$"
}
};
/* eslint-enable */
}