phaser
Version:
A fast, free and fun HTML5 Game Framework for Desktop and Mobile web browsers from the team at Phaser Studio Inc.
699 lines (573 loc) • 21.1 kB
JavaScript
var TextStyle = require('../../../src/gameobjects/text/TextStyle');
// MeasureText requires a Canvas, so we bypass it by always providing pre-built
// metrics in the constructor style (which skips the MeasureText call) and by
// overriding the `update` method on each instance so that font-change setters
// cannot reach MeasureText either.
function createMockParent ()
{
return {
width: 0,
height: 0,
updateText: function () { return this; }
};
}
function createStyle (parent, customStyle)
{
var metrics = { ascent: 10, descent: 2, fontSize: 12 };
var initStyle = Object.assign({ metrics: metrics }, customStyle || {});
var style = new TextStyle(parent, initStyle);
// Prevent any subsequent call from reaching MeasureText
style.update = function (recalculateMetrics)
{
if (recalculateMetrics)
{
this._font = [ this.fontStyle, this.fontSize, this.fontFamily ].join(' ').trim();
}
return this.parent.updateText();
};
return style;
}
function createMockContext ()
{
return {
font: '',
textBaseline: '',
fillStyle: '',
strokeStyle: '',
lineWidth: 0,
lineCap: '',
lineJoin: '',
shadowOffsetX: 0,
shadowOffsetY: 0,
shadowColor: '',
shadowBlur: 0
};
}
describe('TextStyle', function ()
{
var parent;
beforeEach(function ()
{
parent = createMockParent();
});
describe('constructor', function ()
{
it('should set default property values when no style is provided', function ()
{
var style = createStyle(parent);
expect(style.fontFamily).toBe('Courier');
expect(style.fontSize).toBe('16px');
expect(style.fontStyle).toBe('');
expect(style.color).toBe('#fff');
expect(style.stroke).toBe('#fff');
expect(style.strokeThickness).toBe(0);
expect(style.align).toBe('left');
expect(style.maxLines).toBe(0);
expect(style.fixedWidth).toBe(0);
expect(style.fixedHeight).toBe(0);
expect(style.resolution).toBe(0);
expect(style.rtl).toBe(false);
expect(style.backgroundColor).toBeNull();
});
it('should set shadow defaults', function ()
{
var style = createStyle(parent);
expect(style.shadowOffsetX).toBe(0);
expect(style.shadowOffsetY).toBe(0);
expect(style.shadowColor).toBe('#000');
expect(style.shadowBlur).toBe(0);
expect(style.shadowStroke).toBe(false);
expect(style.shadowFill).toBe(false);
});
it('should set word wrap defaults', function ()
{
var style = createStyle(parent);
expect(style.wordWrapWidth).toBeNull();
expect(style.wordWrapCallback).toBeNull();
expect(style.wordWrapCallbackScope).toBeNull();
expect(style.wordWrapUseAdvanced).toBe(false);
});
it('should apply custom style values from the style object', function ()
{
var style = createStyle(parent, {
fontFamily: 'Arial',
fontSize: '32px',
fontStyle: 'bold',
color: '#ff0000',
align: 'center',
maxLines: 5
});
expect(style.fontFamily).toBe('Arial');
expect(style.fontSize).toBe('32px');
expect(style.fontStyle).toBe('bold');
expect(style.color).toBe('#ff0000');
expect(style.align).toBe('center');
expect(style.maxLines).toBe(5);
});
it('should convert a numeric fontSize to a px string', function ()
{
var style = createStyle(parent, { fontSize: 24 });
expect(style.fontSize).toBe('24px');
});
it('should store provided metrics without calling MeasureText', function ()
{
var style = createStyle(parent, {
metrics: { ascent: 20, descent: 5, fontSize: 25 }
});
expect(style.metrics.ascent).toBe(20);
expect(style.metrics.descent).toBe(5);
expect(style.metrics.fontSize).toBe(25);
});
it('should store a reference to the parent object', function ()
{
var style = createStyle(parent);
expect(style.parent).toBe(parent);
});
it('should build the _font string from fontStyle, fontSize and fontFamily', function ()
{
var style = createStyle(parent, {
fontStyle: 'italic',
fontSize: '20px',
fontFamily: 'Arial'
});
expect(style._font).toBe('italic 20px Arial');
});
it('should omit fontStyle from _font when it is empty', function ()
{
var style = createStyle(parent, {
fontStyle: '',
fontSize: '16px',
fontFamily: 'Courier'
});
expect(style._font).toBe('16px Courier');
});
it('should allow fill as an alias for color', function ()
{
var style = createStyle(parent, { fill: '#123456' });
expect(style.color).toBe('#123456');
});
});
describe('setStyle', function ()
{
it('should update properties and return the parent', function ()
{
var style = createStyle(parent);
var result = style.setStyle({ color: '#aabbcc' }, false);
expect(style.color).toBe('#aabbcc');
expect(result).toBe(parent);
});
it('should not call parent.updateText when updateText is false', function ()
{
var style = createStyle(parent);
var callCount = 0;
parent.updateText = function () { callCount++; return parent; };
style.setStyle({ color: '#aabbcc' }, false);
expect(callCount).toBe(0);
});
});
describe('setFont', function ()
{
it('should parse a two-part string into fontSize and fontFamily', function ()
{
var style = createStyle(parent);
style.setFont('16px Arial', false);
expect(style.fontFamily).toBe('Arial');
expect(style.fontSize).toBe('16px');
expect(style.fontStyle).toBe('');
});
it('should parse a three-part string into fontStyle, fontSize and fontFamily', function ()
{
var style = createStyle(parent);
style.setFont('bold 24px Georgia', false);
expect(style.fontStyle).toBe('bold');
expect(style.fontSize).toBe('24px');
expect(style.fontFamily).toBe('Georgia');
});
it('should accept an object with fontFamily, fontSize and fontStyle', function ()
{
var style = createStyle(parent);
style.setFont({ fontFamily: 'Verdana', fontSize: '18px', fontStyle: 'italic' }, false);
expect(style.fontFamily).toBe('Verdana');
expect(style.fontSize).toBe('18px');
expect(style.fontStyle).toBe('italic');
});
it('should return the parent object', function ()
{
var style = createStyle(parent);
var result = style.setFont('16px Courier', false);
expect(result).toBe(parent);
});
});
describe('setFontSize', function ()
{
it('should convert a number to a px string', function ()
{
var style = createStyle(parent);
style.setFontSize(48);
expect(style.fontSize).toBe('48px');
});
it('should accept a string with a CSS unit directly', function ()
{
var style = createStyle(parent);
style.setFontSize('2em');
expect(style.fontSize).toBe('2em');
});
});
describe('setColor and setFill', function ()
{
it('setColor should update the color property', function ()
{
var style = createStyle(parent);
style.setColor('#ff00ff');
expect(style.color).toBe('#ff00ff');
});
it('setFill should also update the color property', function ()
{
var style = createStyle(parent);
style.setFill('rgba(0,255,0,0.5)');
expect(style.color).toBe('rgba(0,255,0,0.5)');
});
});
describe('setBackgroundColor', function ()
{
it('should set the backgroundColor property', function ()
{
var style = createStyle(parent);
style.setBackgroundColor('#336699');
expect(style.backgroundColor).toBe('#336699');
});
});
describe('setResolution', function ()
{
it('should set the resolution property', function ()
{
var style = createStyle(parent);
style.setResolution(2);
expect(style.resolution).toBe(2);
});
});
describe('setStroke', function ()
{
it('should set stroke color and thickness', function ()
{
var style = createStyle(parent);
style.setStroke('#ff0000', 4);
expect(style.stroke).toBe('#ff0000');
expect(style.strokeThickness).toBe(4);
});
it('should reset strokeThickness to zero when called with no arguments and thickness was non-zero', function ()
{
var style = createStyle(parent, { stroke: '#ff0000', strokeThickness: 4 });
style.setStroke();
expect(style.strokeThickness).toBe(0);
});
});
describe('setShadow', function ()
{
it('should set all shadow properties', function ()
{
var style = createStyle(parent);
style.setShadow(5, 10, '#ff0000', 8, true, false);
expect(style.shadowOffsetX).toBe(5);
expect(style.shadowOffsetY).toBe(10);
expect(style.shadowColor).toBe('#ff0000');
expect(style.shadowBlur).toBe(8);
expect(style.shadowStroke).toBe(true);
expect(style.shadowFill).toBe(false);
});
it('should use defaults when called with no arguments', function ()
{
var style = createStyle(parent);
style.setShadow();
expect(style.shadowOffsetX).toBe(0);
expect(style.shadowOffsetY).toBe(0);
expect(style.shadowColor).toBe('#000');
expect(style.shadowBlur).toBe(0);
expect(style.shadowStroke).toBe(false);
expect(style.shadowFill).toBe(true);
});
it('should return the parent object', function ()
{
var style = createStyle(parent);
var result = style.setShadow(1, 1, '#000', 0);
expect(result).toBe(parent);
});
});
describe('setShadowOffset', function ()
{
it('should apply a single argument to both x and y', function ()
{
var style = createStyle(parent);
style.setShadowOffset(7);
expect(style.shadowOffsetX).toBe(7);
expect(style.shadowOffsetY).toBe(7);
});
it('should set x and y independently', function ()
{
var style = createStyle(parent);
style.setShadowOffset(3, 9);
expect(style.shadowOffsetX).toBe(3);
expect(style.shadowOffsetY).toBe(9);
});
});
describe('setShadowColor', function ()
{
it('should set the shadowColor property', function ()
{
var style = createStyle(parent);
style.setShadowColor('#aabbcc');
expect(style.shadowColor).toBe('#aabbcc');
});
it('should default to #000 when called with no argument', function ()
{
var style = createStyle(parent);
style.setShadowColor();
expect(style.shadowColor).toBe('#000');
});
});
describe('setShadowBlur', function ()
{
it('should set the shadowBlur property', function ()
{
var style = createStyle(parent);
style.setShadowBlur(12);
expect(style.shadowBlur).toBe(12);
});
it('should default to zero when called with no argument', function ()
{
var style = createStyle(parent);
style.setShadowBlur();
expect(style.shadowBlur).toBe(0);
});
});
describe('setShadowStroke and setShadowFill', function ()
{
it('setShadowStroke should set the shadowStroke property', function ()
{
var style = createStyle(parent);
style.setShadowStroke(true);
expect(style.shadowStroke).toBe(true);
});
it('setShadowFill should set the shadowFill property', function ()
{
var style = createStyle(parent);
style.setShadowFill(true);
expect(style.shadowFill).toBe(true);
});
});
describe('setWordWrapWidth', function ()
{
it('should set the word wrap width with basic wrapping', function ()
{
var style = createStyle(parent);
style.setWordWrapWidth(300);
expect(style.wordWrapWidth).toBe(300);
expect(style.wordWrapUseAdvanced).toBe(false);
});
it('should enable advanced wrapping when the flag is true', function ()
{
var style = createStyle(parent);
style.setWordWrapWidth(200, true);
expect(style.wordWrapWidth).toBe(200);
expect(style.wordWrapUseAdvanced).toBe(true);
});
it('should accept null to disable wrapping', function ()
{
var style = createStyle(parent);
style.setWordWrapWidth(null);
expect(style.wordWrapWidth).toBeNull();
});
});
describe('setWordWrapCallback', function ()
{
it('should set a callback and its scope', function ()
{
var style = createStyle(parent);
var cb = function () {};
var scope = { foo: 'bar' };
style.setWordWrapCallback(cb, scope);
expect(style.wordWrapCallback).toBe(cb);
expect(style.wordWrapCallbackScope).toBe(scope);
});
it('should default scope to null', function ()
{
var style = createStyle(parent);
style.setWordWrapCallback(function () {});
expect(style.wordWrapCallbackScope).toBeNull();
});
});
describe('setAlign', function ()
{
it('should set the align property', function ()
{
var style = createStyle(parent);
style.setAlign('center');
expect(style.align).toBe('center');
});
it('should default to left when called with no argument', function ()
{
var style = createStyle(parent, { align: 'right' });
style.setAlign();
expect(style.align).toBe('left');
});
});
describe('setMaxLines', function ()
{
it('should set the maxLines property', function ()
{
var style = createStyle(parent);
style.setMaxLines(10);
expect(style.maxLines).toBe(10);
});
it('should default to zero when called with no argument', function ()
{
var style = createStyle(parent, { maxLines: 5 });
style.setMaxLines();
expect(style.maxLines).toBe(0);
});
});
describe('setFixedSize', function ()
{
it('should set fixedWidth and fixedHeight', function ()
{
var style = createStyle(parent);
style.setFixedSize(200, 100);
expect(style.fixedWidth).toBe(200);
expect(style.fixedHeight).toBe(100);
});
it('should update parent width and height when values are non-zero', function ()
{
var style = createStyle(parent);
style.setFixedSize(400, 300);
expect(parent.width).toBe(400);
expect(parent.height).toBe(300);
});
it('should not override parent dimensions when values are zero', function ()
{
parent.width = 50;
parent.height = 50;
var style = createStyle(parent);
style.setFixedSize(0, 0);
expect(parent.width).toBe(50);
expect(parent.height).toBe(50);
});
});
describe('syncFont', function ()
{
it('should set context.font to the internal _font string', function ()
{
var style = createStyle(parent, {
fontStyle: 'bold',
fontSize: '20px',
fontFamily: 'Arial'
});
var ctx = createMockContext();
style.syncFont(null, ctx);
expect(ctx.font).toBe('bold 20px Arial');
});
});
describe('syncStyle', function ()
{
it('should set fill, stroke and line properties on the context', function ()
{
var style = createStyle(parent, {
color: '#aabbcc',
stroke: '#112233',
strokeThickness: 3
});
var ctx = createMockContext();
style.syncStyle(null, ctx);
expect(ctx.textBaseline).toBe('alphabetic');
expect(ctx.fillStyle).toBe('#aabbcc');
expect(ctx.strokeStyle).toBe('#112233');
expect(ctx.lineWidth).toBe(3);
expect(ctx.lineCap).toBe('round');
expect(ctx.lineJoin).toBe('round');
});
});
describe('syncShadow', function ()
{
it('should apply shadow settings to context when enabled', function ()
{
var style = createStyle(parent);
style.setShadow(4, 6, '#ff0000', 10);
var ctx = createMockContext();
style.syncShadow(ctx, true);
expect(ctx.shadowOffsetX).toBe(4);
expect(ctx.shadowOffsetY).toBe(6);
expect(ctx.shadowColor).toBe('#ff0000');
expect(ctx.shadowBlur).toBe(10);
});
it('should zero out shadow settings when disabled', function ()
{
var style = createStyle(parent);
var ctx = createMockContext();
ctx.shadowOffsetX = 5;
ctx.shadowOffsetY = 5;
ctx.shadowColor = '#ff0000';
ctx.shadowBlur = 8;
style.syncShadow(ctx, false);
expect(ctx.shadowOffsetX).toBe(0);
expect(ctx.shadowOffsetY).toBe(0);
expect(ctx.shadowColor).toBe(0);
expect(ctx.shadowBlur).toBe(0);
});
});
describe('getTextMetrics', function ()
{
it('should return an object with ascent, descent and fontSize', function ()
{
var style = createStyle(parent, {
metrics: { ascent: 15, descent: 3, fontSize: 18 }
});
var metrics = style.getTextMetrics();
expect(metrics.ascent).toBe(15);
expect(metrics.descent).toBe(3);
expect(metrics.fontSize).toBe(18);
});
it('should return a copy, not the original metrics object', function ()
{
var style = createStyle(parent, {
metrics: { ascent: 10, descent: 2, fontSize: 12 }
});
var metrics = style.getTextMetrics();
metrics.ascent = 999;
expect(style.metrics.ascent).toBe(10);
});
});
describe('toJSON', function ()
{
it('should include all property map keys in the output', function ()
{
var style = createStyle(parent);
var json = style.toJSON();
expect(json.fontFamily).toBe('Courier');
expect(json.fontSize).toBe('16px');
expect(json.color).toBe('#fff');
expect(json.align).toBe('left');
expect(json.maxLines).toBe(0);
expect(json.shadowStroke).toBe(false);
expect(json.wordWrapWidth).toBeNull();
});
it('should include a metrics object in the output', function ()
{
var style = createStyle(parent, {
metrics: { ascent: 10, descent: 2, fontSize: 12 }
});
var json = style.toJSON();
expect(json.metrics).toBeDefined();
expect(json.metrics.ascent).toBe(10);
expect(json.metrics.descent).toBe(2);
expect(json.metrics.fontSize).toBe(12);
});
});
describe('destroy', function ()
{
it('should set parent to undefined', function ()
{
var style = createStyle(parent);
style.destroy();
expect(style.parent).toBeUndefined();
});
});
});