phaser
Version:
A fast, free and fun HTML5 Game Framework for Desktop and Mobile web browsers from the team at Phaser Studio Inc.
609 lines (526 loc) • 17.7 kB
JavaScript
var CanvasSnapshot = require('../../../src/renderer/snapshot/CanvasSnapshot');
var CanvasPool = require('../../../src/display/canvas/CanvasPool');
describe('Phaser.Renderer.Snapshot.Canvas', function ()
{
var mockCanvas;
var mockCallback;
var mockContext;
var MockImage;
var mockCopyCanvas;
var mockCopyContext;
var createWebGLSpy;
var removeSpy;
beforeEach(function ()
{
mockCallback = vi.fn();
mockContext = {
getImageData: vi.fn().mockReturnValue({
data: [255, 0, 128, 255]
}),
drawImage: vi.fn()
};
mockCanvas = {
width: 800,
height: 600,
getContext: vi.fn().mockReturnValue(mockContext),
toDataURL: vi.fn().mockReturnValue('data:image/png;base64,fullcanvas')
};
mockCopyContext = {
drawImage: vi.fn()
};
mockCopyCanvas = {
width: 100,
height: 100,
getContext: vi.fn().mockReturnValue(mockCopyContext),
toDataURL: vi.fn().mockReturnValue('data:image/png;base64,copycanvas')
};
createWebGLSpy = vi.spyOn(CanvasPool, 'createWebGL').mockReturnValue(mockCopyCanvas);
removeSpy = vi.spyOn(CanvasPool, 'remove').mockImplementation(function () {});
// Mock Image constructor — triggers onload immediately on src assignment
MockImage = vi.fn().mockImplementation(function ()
{
var self = this;
self.onload = null;
self.onerror = null;
Object.defineProperty(self, 'src',
{
set: function (value)
{
self._src = value;
if (self.onload)
{
self.onload();
}
},
get: function ()
{
return self._src;
}
});
});
vi.stubGlobal('Image', MockImage);
});
afterEach(function ()
{
vi.restoreAllMocks();
vi.unstubAllGlobals();
});
// -------------------------------------------------------------------------
// getPixel mode
// -------------------------------------------------------------------------
describe('getPixel mode', function ()
{
it('should call the callback with a Color object', function ()
{
CanvasSnapshot(mockCanvas,
{
callback: mockCallback,
getPixel: true,
x: 10,
y: 20
});
expect(mockCallback).toHaveBeenCalledOnce();
expect(mockCallback.mock.calls[0][0]).toBeDefined();
});
it('should sample the correct pixel coordinates', function ()
{
CanvasSnapshot(mockCanvas,
{
callback: mockCallback,
getPixel: true,
x: 5,
y: 15
});
expect(mockContext.getImageData).toHaveBeenCalledWith(5, 15, 1, 1);
});
it('should use absolute values for negative x and y', function ()
{
CanvasSnapshot(mockCanvas,
{
callback: mockCallback,
getPixel: true,
x: -10,
y: -20
});
expect(mockContext.getImageData).toHaveBeenCalledWith(10, 20, 1, 1);
});
it('should round fractional coordinates', function ()
{
CanvasSnapshot(mockCanvas,
{
callback: mockCallback,
getPixel: true,
x: 4.7,
y: 3.2
});
expect(mockContext.getImageData).toHaveBeenCalledWith(5, 3, 1, 1);
});
it('should default x and y to 0 when not provided', function ()
{
CanvasSnapshot(mockCanvas,
{
callback: mockCallback,
getPixel: true
});
expect(mockContext.getImageData).toHaveBeenCalledWith(0, 0, 1, 1);
});
it('should pass the correct red channel value to the Color', function ()
{
mockContext.getImageData.mockReturnValue({ data: [100, 150, 200, 255] });
CanvasSnapshot(mockCanvas,
{
callback: mockCallback,
getPixel: true,
x: 0,
y: 0
});
var color = mockCallback.mock.calls[0][0];
expect(color.red).toBe(100);
});
it('should pass the correct green channel value to the Color', function ()
{
mockContext.getImageData.mockReturnValue({ data: [100, 150, 200, 255] });
CanvasSnapshot(mockCanvas,
{
callback: mockCallback,
getPixel: true,
x: 0,
y: 0
});
var color = mockCallback.mock.calls[0][0];
expect(color.green).toBe(150);
});
it('should pass the correct blue channel value to the Color', function ()
{
mockContext.getImageData.mockReturnValue({ data: [100, 150, 200, 255] });
CanvasSnapshot(mockCanvas,
{
callback: mockCallback,
getPixel: true,
x: 0,
y: 0
});
var color = mockCallback.mock.calls[0][0];
expect(color.blue).toBe(200);
});
it('should pass the correct alpha channel value to the Color', function ()
{
mockContext.getImageData.mockReturnValue({ data: [100, 150, 200, 128] });
CanvasSnapshot(mockCanvas,
{
callback: mockCallback,
getPixel: true,
x: 0,
y: 0
});
var color = mockCallback.mock.calls[0][0];
expect(color.alpha).toBe(128);
});
it('should not use CanvasPool in getPixel mode', function ()
{
CanvasSnapshot(mockCanvas,
{
callback: mockCallback,
getPixel: true,
x: 0,
y: 0
});
expect(createWebGLSpy).not.toHaveBeenCalled();
});
});
// -------------------------------------------------------------------------
// Full canvas capture mode
// -------------------------------------------------------------------------
describe('full canvas capture', function ()
{
it('should call canvas.toDataURL with default type and encoder', function ()
{
CanvasSnapshot(mockCanvas,
{
callback: mockCallback
});
expect(mockCanvas.toDataURL).toHaveBeenCalledWith('image/png', 0.92);
});
it('should call the callback with the image on successful load', function ()
{
CanvasSnapshot(mockCanvas,
{
callback: mockCallback
});
expect(mockCallback).toHaveBeenCalledOnce();
expect(mockCallback.mock.calls[0][0]).toBeInstanceOf(MockImage);
});
it('should call canvas.toDataURL with custom type and encoder', function ()
{
CanvasSnapshot(mockCanvas,
{
callback: mockCallback,
type: 'image/jpeg',
encoder: 0.8
});
expect(mockCanvas.toDataURL).toHaveBeenCalledWith('image/jpeg', 0.8);
});
it('should call the callback with no argument on image error', function ()
{
MockImage.mockImplementation(function ()
{
var self = this;
self.onload = null;
self.onerror = null;
Object.defineProperty(self, 'src',
{
set: function (value)
{
self._src = value;
if (self.onerror)
{
self.onerror();
}
},
get: function ()
{
return self._src;
}
});
});
CanvasSnapshot(mockCanvas,
{
callback: mockCallback
});
expect(mockCallback).toHaveBeenCalledOnce();
expect(mockCallback.mock.calls[0][0]).toBeUndefined();
});
it('should not use CanvasPool for full canvas capture', function ()
{
CanvasSnapshot(mockCanvas,
{
callback: mockCallback
});
expect(createWebGLSpy).not.toHaveBeenCalled();
});
it('should set image.src to the data URL returned by canvas.toDataURL', function ()
{
var capturedSrc = null;
MockImage.mockImplementation(function ()
{
var self = this;
self.onload = null;
self.onerror = null;
Object.defineProperty(self, 'src',
{
set: function (value)
{
capturedSrc = value;
self._src = value;
if (self.onload)
{
self.onload();
}
},
get: function ()
{
return self._src;
}
});
});
CanvasSnapshot(mockCanvas,
{
callback: mockCallback
});
expect(capturedSrc).toBe('data:image/png;base64,fullcanvas');
});
});
// -------------------------------------------------------------------------
// Area (partial) capture mode
// -------------------------------------------------------------------------
describe('area capture', function ()
{
it('should use CanvasPool.createWebGL when x is non-zero', function ()
{
CanvasSnapshot(mockCanvas,
{
callback: mockCallback,
x: 10,
y: 0,
width: 800,
height: 600
});
expect(createWebGLSpy).toHaveBeenCalled();
});
it('should use CanvasPool.createWebGL when y is non-zero', function ()
{
CanvasSnapshot(mockCanvas,
{
callback: mockCallback,
x: 0,
y: 10,
width: 800,
height: 600
});
expect(createWebGLSpy).toHaveBeenCalled();
});
it('should use CanvasPool.createWebGL when width differs from canvas width', function ()
{
CanvasSnapshot(mockCanvas,
{
callback: mockCallback,
x: 0,
y: 0,
width: 400,
height: 600
});
expect(createWebGLSpy).toHaveBeenCalled();
});
it('should use CanvasPool.createWebGL when height differs from canvas height', function ()
{
CanvasSnapshot(mockCanvas,
{
callback: mockCallback,
x: 0,
y: 0,
width: 800,
height: 300
});
expect(createWebGLSpy).toHaveBeenCalled();
});
it('should call drawImage with the correct source region and destination', function ()
{
CanvasSnapshot(mockCanvas,
{
callback: mockCallback,
x: 10,
y: 20,
width: 100,
height: 200
});
expect(mockCopyContext.drawImage).toHaveBeenCalledWith(
mockCanvas, 10, 20, 100, 200, 0, 0, 100, 200
);
});
it('should not call drawImage when width is zero', function ()
{
CanvasSnapshot(mockCanvas,
{
callback: mockCallback,
x: 10,
y: 10,
width: 0,
height: 100
});
expect(mockCopyContext.drawImage).not.toHaveBeenCalled();
});
it('should not call drawImage when height is zero', function ()
{
CanvasSnapshot(mockCanvas,
{
callback: mockCallback,
x: 10,
y: 10,
width: 100,
height: 0
});
expect(mockCopyContext.drawImage).not.toHaveBeenCalled();
});
it('should call CanvasPool.remove with the copy canvas after load', function ()
{
CanvasSnapshot(mockCanvas,
{
callback: mockCallback,
x: 10,
y: 10,
width: 100,
height: 100
});
expect(removeSpy).toHaveBeenCalledWith(mockCopyCanvas);
});
it('should call CanvasPool.remove with the copy canvas after error', function ()
{
MockImage.mockImplementation(function ()
{
var self = this;
self.onload = null;
self.onerror = null;
Object.defineProperty(self, 'src',
{
set: function (value)
{
self._src = value;
if (self.onerror)
{
self.onerror();
}
},
get: function ()
{
return self._src;
}
});
});
CanvasSnapshot(mockCanvas,
{
callback: mockCallback,
x: 10,
y: 10,
width: 100,
height: 100
});
expect(removeSpy).toHaveBeenCalledWith(mockCopyCanvas);
});
it('should call the callback with the image on successful area load', function ()
{
CanvasSnapshot(mockCanvas,
{
callback: mockCallback,
x: 10,
y: 10,
width: 100,
height: 100
});
expect(mockCallback).toHaveBeenCalledOnce();
expect(mockCallback.mock.calls[0][0]).toBeInstanceOf(MockImage);
});
it('should call the callback with no argument on area image error', function ()
{
MockImage.mockImplementation(function ()
{
var self = this;
self.onload = null;
self.onerror = null;
Object.defineProperty(self, 'src',
{
set: function (value)
{
self._src = value;
if (self.onerror)
{
self.onerror();
}
},
get: function ()
{
return self._src;
}
});
});
CanvasSnapshot(mockCanvas,
{
callback: mockCallback,
x: 10,
y: 10,
width: 100,
height: 100
});
expect(mockCallback).toHaveBeenCalledOnce();
expect(mockCallback.mock.calls[0][0]).toBeUndefined();
});
it('should use custom type and encoder for area capture toDataURL', function ()
{
CanvasSnapshot(mockCanvas,
{
callback: mockCallback,
x: 10,
y: 10,
width: 100,
height: 100,
type: 'image/jpeg',
encoder: 0.75
});
expect(mockCopyCanvas.toDataURL).toHaveBeenCalledWith('image/jpeg', 0.75);
});
it('should set the image src to the copy canvas data URL', function ()
{
var capturedSrc = null;
MockImage.mockImplementation(function ()
{
var self = this;
self.onload = null;
self.onerror = null;
Object.defineProperty(self, 'src',
{
set: function (value)
{
capturedSrc = value;
self._src = value;
if (self.onload)
{
self.onload();
}
},
get: function ()
{
return self._src;
}
});
});
CanvasSnapshot(mockCanvas,
{
callback: mockCallback,
x: 10,
y: 10,
width: 100,
height: 100
});
expect(capturedSrc).toBe('data:image/png;base64,copycanvas');
});
});
});