๐ Chapter 11: ์๋๋ฐ์ค ํจํด
๐ ๋จ์ ํ ์คํธโ
์๊ตฌ์ฌํญ: ์ฝํผ๋ฐ์ค ํ์ฌ์ ์ ๋ฐ์ ์ธ ์งํ ์ํฉ๊ณผ ์น ์ฌ์ดํธ ์ด์ ์คํ๋ฅผ ํ๋์ ํ์ ํ ์ ์๋ ๋์๋ณด๋๊ฐ ์์์ผ๋ฉด ์ข๊ณ๋ค๊ณ ์ฃผ์ต ๋ด๋น์๋ ๋งํ๋ค.
ํญ๋ชฉ์ ๋ค์๊ณผ ๊ฐ๋ค.
- ์ฝํผ๋ฐ์ค ๋ฑ๋ก์ ์
- ์ฝํผ๋ฐ์ค ๋ฑ๋ก์ ์ฑ๋ช
- ์ฒดํฌ์ธํ ์ฐธ๊ฐ์ ์
- ์ฒดํฌ์ธํ ์ฐธ๊ฐ์ ์ฑ๋ช
- ์๋ํํฐ ์์ฅ API์ ํธ์ถ ํ์
- ์ง์ญ ๊ณตํญ ๊ธฐ์ ์๋ณด
๐ ์์ ฏ ์๋๋ฐ์ค ๋ง๋ค๊ธฐโ
์์ ฏ ์๋๋ฐ์ค์ ๋ชฉ์ ์ ๊ฐ ์์ ฏ์ ๋ถ๋ฆฌํ์ฌ ์์์ ์์ง์ด๊ฒ ํ๋ ๊ฒ์ด๋ค. ๊ทธ๋ฆฌ๊ณ ์๋๋ฐ์ค ํจํด์ ์ด์ฉํ๋ฉด ์์ ฏ๋ง๋ค ํ์ ๋ ์์กด์ฑ ์ ๋ฌผ ์ธํธ๋ฅผ ์ฆ์ ํ์ฌ ๊ฐ์ ์๋ฌด๋ฅผ ์์ํ๋ ๋ฐ ํ์ํ ๋๊ตฌ๋ฅผ ๊ณต์ํ ์ ์๋ค.
์์ ฏ ์๋๋ฐ์ค๋ฅผ ์ธ์คํด์คํโ
WidgetSandbox ์์ฑ์ ํจ์๋ new ํค์๋๋ฅผ ์ฌ์ฉํด์ผ ํ๊ณ , ์ ์ด๋ ํ๋์ ์ธ์, ์ฆ ์๋๋ฐ์ค์ ๊ฒฉ๋ฆฌํ ์์ ฏ ์์ฑ ํจ์๋ฅผ ๋ฐ๋๋ก ์์ฑํ๋ค. ๋จผ์ , ๊ธฐ๋ฅ ์ ๊ฒ์ฉ ๋จ์ ํ
์คํธ๋ฅผ ๋ง๋ ๋ค.
describe('Conference.WidgetSandbox', () => {
'use strict';
describe('์์ฑ์ ํจ์', () => {
it('"new" ํค์๋๋ก ์คํํ์ง ์์ผ๋ฉด ์์ธ๋ฅผ ๋์ง๋ค', () => {
expect(function shouldThrow() {
var sandbox = Conference.WidgetSandbox();
}).toThrowError(Conference.WidgetSandbox.messages.mustBeCalledWithNew);
});
it('์์ ฏ ํจ์๊ฐ ๋๋ฝ๋๋ฉด ์์ธ๋ฅผ ๋์ง๋ค', () => {
[null, undefined, 1, 'SomeString', false].forEach(function testInvalid(notAFcn) {
expect(function shouldThrow() {
var sandbox = new Conference.WidgetSandbox(notAFcn);
}).toThrowError(Conference.WidgetSandbox.messages.fcnMustBeProvided);
});
});
it('sandbox๋ฅผ ์ธ์๋ก ์์ ฏ ํจ์๋ฅผ ์คํํ๋ค', () => {
var widgetFcn = jasmine.createSpy();
var sandbox = new Conference.WidgetSandbox(widgetFcn);
expect(widgetFcn).toHaveBeenCalledWith(sandbox);
});
});
});
WidgetSandbox ๊ตฌํ๋ถ๋ฅผ ์์ฑํ๋ค.
var Conference = Conference || {};
Conference.WidgetSandbox = function() {
'use strict';
// Conference.WidgetSandbox(...)๋ฅผ new๋ก ์คํํ๋์ง ๋ณด์ฅํ๋ค.
if (!(this instanceof Conference.WidgetSandbox)) {
throw new Error(Conference.WidgetSandbox.messages.mustBeCalledWithNew);
}
var widgetFunction = arguments[0];
if (typeof widgetFunction !== 'function') {
throw new Error(Conference.WidgetSandbox.messages.fcnMustBeProvided);
}
widgetFunction(this);
};
Conference.WidgetSandbox.messages = {
mustBeCalledWithNew: 'WidgetSandbox ํจ์๋ ๋ฐ๋์ new๋ก ํธ์ถํด์ผ ํฉ๋๋ค',
fcnMustBeProvided: '์์ ฏ ํจ์๋ ํ์ ์
๋ ฅ ํญ๋ชฉ์
๋๋ค',
};
์๋๋ฐ์ค๋ก ์์ ฏ์ ๋๊ตฌ๋ฅผ ์ ๊ณตโ
WidgetSandbox์ ๋ชฉํ๋ ๋์๋ณด๋ ์์ ฏ ๊ฐ ๊ฒฐํฉ๋๋ฅผ ๋ฎ์ถ๊ณ ๋ผ์ด๋๋ ์ผ์ด๋ค. ๊ทธ๋ฌ๋ DOM ์กฐ์, ๋๋ ์น ์๋น์ค๋ฅผ ์ด์ฉํ ๋ฐ์ดํฐ ์กฐํ ๊ฐ์ ๊ธฐ๋ฅ์ด ์ ๋๋ค๋ฉด ์๋ฌด๋ฐ ์ธ๋ชจ๊ฐ ์๋ค.
์ด๋ค ์์ ฏ์์ ์ด๋ค ๋๊ตฌ๊ฐ ํ์ํ์ง ์๊ณ ์์ผ๋ฉด ๋๋ฏ๋ก ๋๊ตฌ ์ธํธ๋ฅผ ๊ณ ์ ํ์ง ๋ง๊ณ ์ ๋๊ตฌ๋ฅผ ์ถ๊ฐํด์ WidgetSandbox ๊ธฐ๋ฅ์ ํ์ฅํ๋ ํธ์ด ๋ซ๋ค๊ณ ํ๋จํ๋ค. ๋ํ, ์์ ฏ๋ง๋ค ์ฌ์ฉ ๊ฐ๋ฅํ ๋๊ตฌ๋ฅผ ์ ํํ ์ ์์ด์ผ ํ๋ค. ์๋ฅผ ๋ค์ด ์น ์๋น์ค ์ฐ๋์ด ์ ํ ํ์ ์๋ ์์ ฏ์ ๊ตณ์ด AJAX ํต์ ๊ด๋ จ ๋๊ตฌ์ ์ ๊ทผํ ๊ถํ์ ์ค ์ด์ ๋ ์๋ค.
์์ ๊ฐ์ ๊ธฐ๋ฅ์ ๊ตฌํํ๊ธฐ ์ ์ ๊ฒฐ์ ํด์ผ ํ ๋ฌธ์ ๊ฐ ์๋ค.
- ๋๊ตฌ๋ ์ด๋์ ์ ์ํ๋?
Conference.WidgetTools์ด๋ฆ๊ณต๊ฐ ๋ด์ ๋๊ตฌ๋ฅผ ์ ์ํ๋ ๊ฒ ๋ง๋ค.
- ๋๊ตฌ๋ฅผ ์ด๋ป๊ฒ
WidgetSandbox์ธ์คํด์ค์ ์ถ๊ฐํ๋?- ๋๊ตฌ๋ฅผ ๋ชจ๋๋ก ์ ์ํ๋ฉด ๋๊ตฌ๋ง๋ค ๋ชจ๋ ํจ์๊ฐ
WidgetSandbox์ธ์คํด์ค๋ฅผ ๋ฐ๊ณ , ๋ค์ ์ฝ๋์ฒ๋ผ ๋๊ตฌ๊ฐ ์ค์ค๋ก๋ฅผWidgetSandboxํ๋กํผํฐ์ ์ถ๊ฐํ๋ค.
- ๋๊ตฌ๋ฅผ ๋ชจ๋๋ก ์ ์ํ๋ฉด ๋๊ตฌ๋ง๋ค ๋ชจ๋ ํจ์๊ฐ
Conference.WidgetTools.toolA = function(sandbox) {
// toolA๋ฅผ sandbox์ ์ถ๊ฐํ๋ค.
sandbox.toolA = {
function1: function() {
// function1 ๊ตฌํ๋ถ
},
function2: function() {
// function2 ๊ตฌํ๋ถ
},
};
};
WidgetSandbox์์ฑ์๋ ๋ค์ ๋ ์ค ํ๋๋ฅผ ๋ฐ๋๋ค.- ์ฒซ ๋ฒ์งธ ์ธ์๋ ์์ ฏ์์ ์ธ ๋๊ตฌ๋ช ์ด ๋ด๊ธด ๋ฐฐ์ด, ๋ ๋ฒ์งธ ์ธ์๋ ์์ ฏ ํจ์๋ค. ๋ค์ ์ฝ๋๋ฅผ ๋ณด์.
var weatherSandbox = new Conference.WidgetSandbox(
['toolA', 'toolB'],
Conference.widgets.weatherWidget,
);- ๋๊ตฌ๋ช ์ ๊ฐ๋ณ ์ธ์๋ก ๋์ดํ๊ณ ์์ ฏ ํจ์๋ฅผ ์ ์ผ ๋ง์ง๋ง ์ธ์์ ๋ฃ๋๋ค.
var weatherSandbox = new Conference.WidgetSandbox(
'toolA', 'toolB', Conference.widgets.weatherWidget,
);
์ด๋ ์ชฝ์ด๋ WidgetSandbox ์์ฑ์์ ๋๊ตฌ๋ช
๋ชฉ๋ก์ ๊ฑด๋ค์ฃผ๋ฉด ์์ ฏ ํจ์๋ฅผ ์ ๋๋ก ์ฐพ๋์ง๋ถํฐ ํ์ธํ์.
describe('Conference.WidgetSandbox', () => {
'use strict';
describe('์์ฑ์ ํจ์', () => {
it('"new" ํค์๋๋ก ์คํํ์ง ์์ผ๋ฉด ์์ธ๋ฅผ ๋์ง๋ค', () => {
expect(function shouldThrow() {
var sandbox = Conference.WidgetSandbox();
}).toThrowError(Conference.WidgetSandbox.messages.mustBeCalledWithNew);
});
describe('new WidgetSandbox(toolsArray, widgetModule)', () => {
// ๋๊ตฌ ๋ชฉ๋ก์ ๋ฐฐ์ด ํํ๋ก ๋๊ฒผ์ ๋ ์๋ ์ฌ๋ถ๋ฅผ ํ
์คํธ
it('์์ ฏ ํจ์๊ฐ ๋๋ฝ๋๋ฉด ์์ธ๋ฅผ ๋์ง๋ค', () => {
[null, undefined, 1, 'SomeString', false].forEach(function testInvalid(val) {
expect(function shouldThrow() {
var sandbox = new Conference.WidgetSandbox(['tool1', 'tool2'], val);
}).toThrowError(Conference.WidgetSandbox.messages.fcnMustBeProvided);
});
});
it('sandbox๋ฅผ ์ธ์๋ก ์์ ฏ ํจ์๋ฅผ ์คํํ๋ค', () => {
var widgetFcn = jasmine.createSpy();
var sandbox = new Conference.WidgetSandbox(['too1', 'too2'], widgetFcn);
expect(widgetFcn).toHaveBeenCalledWith(sandbox);
});
});
describe("new WidgetSandbox('too1', ..., 'toolN', widgetModule)", () => {
// ๋๊ตฌ ๋ชฉ๋ก์ ๊ฐ๋ณ ์ธ์ ํํ๋ก ๋๊ฒผ์ ๋ ์๋ ์ฌ๋ถ๋ฅผ ํ
์คํธ
it('์์ ฏ ํจ์๊ฐ ๋๋ฝ๋๋ฉด ์์ธ๋ฅผ ๋์ง๋ค', () => {
[null, undefined, 1, 'SomeString', false].forEach(function testInvalid(val) {
expect(function shouldThrow() {
var sandbox = new Conference.WidgetSandbox('tool1', 'tool2', val);
}).toThrowError(Conference.WidgetSandbox.messages.fcnMustBeProvided);
});
});
it('sandbox๋ฅผ ์ธ์๋ก ์์ ฏ ํจ์๋ฅผ ์คํํ๋ค', () => {
var widgetFcn = jasmine.createSpy();
var sandbox = new Conference.WidgetSandbox('too1', 'too2', widgetFcn);
expect(widgetFcn).toHaveBeenCalledWith(sandbox);
});
});
});
});
์ด์ ์์ ฏ ํจ์๋ฅผ ์ ํํ ๊ณจ๋ผ๋ด๋๋ก WidgetSandbox ๊ตฌํ๋ถ๋ฅผ ์์ ํ์. WidgetTools ์ด๋ฆ๊ณต๊ฐ์ ์ผ๋จ ๋น ๊ฐ์ฒด๋ก ์ด๊ธฐํํ๋ค.
var Conference = Conference || {};
Conference.WidgetSandbox = function() {
'use strict';
// Conference.WidgetSandbox(...)๋ฅผ new๋ก ์คํํ๋์ง ๋ณด์ฅํ๋ค.
if (!(this instanceof Conference.WidgetSandbox)) {
throw new Error(Conference.WidgetSandbox.messages.mustBeCalledWithNew);
}
var widgetFunction = arguments[arguments.length - 1];
if (typeof widgetFunction !== 'function') {
throw new Error(Conference.WidgetSandbox.messages.fcnMustBeProvided);
}
widgetFunction(this);
};
// ๋น ๋๊ตฌ ์ด๋ฆ๊ณต๊ฐ์ ์์ฑํ๋ค.
Conference.WidgetTools = {};
Conference.WidgetSandbox.messages = {
mustBeCalledWithNew: 'WidgetSandbox ํจ์๋ ๋ฐ๋์ new๋ก ํธ์ถํด์ผ ํฉ๋๋ค',
fcnMustBeProvided: '์์ ฏ ํจ์๋ ํ์ ์
๋ ฅ ํญ๋ชฉ์
๋๋ค',
};
๋จ์ ํ ์คํธ๋ ๋ชจ๋ ์ฑ๊ณตํ๋ค.
๋ค์ ๋จ๊ณ๋ WidgetSandbox ์์ฑ์ ํจ์์ ์ ๋ฌํ ๋๊ตฌ๋ช
์์ ๋๊ตฌ ๋ชจ๋ ํจ์๋ฅผ ์ฐพ์ ๋๊ตฌ ์ธ์คํด์ค๋ฅผ ์์ฑํ๋ ์ผ์ด๋ค. ๋จผ์ ๋๊ตฌ๋ช
๋ชฉ๋ก์ ๋ฐฐ์ด๋ก ๋๊ธฐ๋ ํํ๋ฅผ ํด๋ณธ๋ค. ์ ๋ฌ๋ ๋๊ตฌ๋ช
์ ๊ฐ๊ฐ Conference.WidgetTools ํ๋กํผํฐ์ ๋์๋๋ค. ์ด ์ด๋ฆ๊ณต๊ฐ์ ๋๊ตฌ๋ช
์ ํด๋นํ๋ ํ๋กํผํฐ๊ฐ ์์ผ๋ฉด ๋ฉ์์ง๋ง ๋ด๋ ์๋ฏธ๊ฐ ๋ถ๋ช
ํ ์๋ฌ๋ฅผ ๋์ ธ์ผ ํ๋ค.
๋๊ตฌ๋ช
์ด ์ ํจํ ๋๊ตฌ๋ช
WidgetSandbox ์ธ์คํด์ค๋ฅผ ์ ์ผํ ์ธ์๋ก ํด๋น ๋๊ตฌ ๋ชจ๋ ํจ์๊ฐ ์คํ๋ ๊ฒ์ด๋ค.
describe('Conference.WidgetSandbox', () => {
'use strict';
describe('์์ฑ์ ํจ์', () => {
var widgetFcnSpy;
beforeEach(() => {
// ํ
์คํธ๊ฐ ์ค์ ๋๊ตฌ์ ๊ตฌ์ ๋ฐ์ง ์๊ฒ ํ
์คํธ ๋๊ตฌ๋ฅผ ์ถ๊ฐํ๋ค.
Conference.WidgetTools.tool1 = function(sandbox) {
return {};
};
Conference.WidgetTools.tool2 = function(sandbox) {
return {};
};
// ์์ ฏ ํจ์ ์ญํ ์ ๋์ ํ ์คํ์ด๋ฅผ ๋ง๋ ๋ค.
widgetFcnSpy = jasmine.createSpy();
});
afterEach(() => {
// ํ
์คํธ ๋๊ตฌ๋ฅผ ์ญ์ ํ๋ค.
delete Conference.WidgetTools.tool1;
delete Conference.WidgetTools.tool2;
});
/** ์ด์ ํ
์คํธ ์ค์ **/
describe('new WidgetSandbox(toolsArray, widgetFnc)', () => {
// ๋๊ตฌ ๋ชฉ๋ก์ ๋ฐฐ์ด ํํ๋ก ๋๊ฒผ์ ๋ ์๋ ์ฌ๋ถ๋ฅผ ํ
์คํธ
/** ์ด์ ํ
์คํธ ์ค์ **/
it('์ฌ๋ฐ๋ฅด์ง ์์ ๋๊ตฌ๋ฅผ ์ง์ ํ๋ฉด ์์ธ๋ฅผ ๋์ง๋ค', () => {
var badTool = 'badTool';
expect(function shouldThrow() {
var sandbox = new Conference.WidgetSandbox(['tool1', badTool], widgetFcnSpy);
}).toThrowError(Conference.WidgetSandbox.messages.unknownTool + badTool);
});
it('๋๊ตฌ ๋ชจ๋ ํจ์๋ฅผ sandbox์์ ์คํํ๋ค', () => {
spyOn(Conference.WidgetTools, 'tool1');
spyOn(Conference.WidgetTools, 'tool2');
var sandbox = new Conference.WidgetSandbox(['tool1', 'tool2'], widgetFcnSpy);
expect(Conference.WidgetTools.tool1).toHaveBeenCalledWith(sandbox);
expect(Conference.WidgetTools.tool2).toHaveBeenCalledWith(sandbox);
});
});
describe("new WidgetSandbox('tool1', ..., 'toolN', widgetFcn)", () => {
/** ์ด์ ํ
์คํธ ์ค์ **/
});
});
});
๋ค์๊ณผ ๊ฐ์ด WidgetSandbox๋ฅผ ์์ ํ๋ฉด ์ ๋จ์ ํ
์คํธ๋ ์ฑ๊ณตํ๋ค.
var Conference = Conference || {};
Conference.WidgetSandbox = function() {
'use strict';
// Conference.WidgetSandbox(...)๋ฅผ new๋ก ์คํํ๋์ง ๋ณด์ฅํ๋ค.
if (!(this instanceof Conference.WidgetSandbox)) {
throw new Error(Conference.WidgetSandbox.messages.mustBeCalledWithNew);
}
var widgetFunction = arguments[arguments.length - 1];
var toolsToLoad = [];
if (typeof widgetFunction !== 'function') {
throw new Error(Conference.WidgetSandbox.messages.fcnMustBeProvided);
}
if (arguments[0] instanceof Array) {
toolsToLoad = arguments[0];
}
toolsToLoad.forEach(function loadTool(toolName) {
if (!Conference.WidgetTools.hasOwnProperty(toolName)) {
throw new Error(Conference.WidgetSandbox.messages.unKnownTool + toolName);
}
Conference.WidgetTools[toolName](this);
}, this); // ์ฝ๋ฐฑ ๋ด์์ this๊ฐ sandbox ์ธ์คํด์ค๋ฅผ ๊ฐ๋ฆฌํค๋๋ก ๋ณด์ฅํ๋ค.
widgetFunction(this);
};
// ๋น ๋๊ตฌ ์ด๋ฆ๊ณต๊ฐ์ ์์ฑํ๋ค.
Conference.WidgetTools = {};
Conference.WidgetSandbox.messages = {
mustBeCalledWithNew: 'WidgetSandbox ํจ์๋ ๋ฐ๋์ new๋ก ํธ์ถํด์ผ ํฉ๋๋ค',
fcnMustBeProvided: '์์ ฏ ํจ์๋ ํ์ ์
๋ ฅ ํญ๋ชฉ์
๋๋ค',
unknownTool: '์ ์ ์๋ ๋๊ตฌ์
๋๋ค',
};
์ด์ ๋ง์ง๋ง์ผ๋ก ์ฌ๋ฌ ๋๊ตฌ๋ช ์ ๊ฐ๋ณ ์ธ์๋ก ์ ๋ฌํ๋ ๊ฒฝ์ฐ๊ฐ ๋จ์๋ค. ๋ฐฐ์ด ์ผ์ด์ค์ ๋จ์ ํ ์คํธ๋ ๊ฑฐ์ ๊ฐ์ง๋ง, ์ง๊ธ์ ์คํจํ๋ค.
describe('Conference.WidgetSandbox', () => {
'use strict';
describe('์์ฑ์ ํจ์', () => {
var widgetFcnSpy;
/** ์ด์ beforeEach/afterEach ๋ธ๋ก์ ์ค์ **/
/** ์ด์ ํ
์คํธ ์ค์ **/
describe('new WidgetSandbox(toolsArray, widgetFcn)', () => {
// ๋๊ตฌ ๋ชฉ๋ก์ ๋ฐฐ์ด ํํ๋ก ๋๊ฒผ์ ๋ ์๋ ์ฌ๋ถ๋ฅผ ํ
์คํธ
/** ์ด์ ํ
์คํธ ์ค์ **/
});
describe("new WidgetSandbox('tool1', ..., 'toolN', widgetFcn)", () => {
// ๋๊ตฌ ๋ชฉ๋ก์ ๊ฐ๋ณ ์ธ์ ํํ๋ก ๋๊ฒผ์ ๋ ์๋ ์ฌ๋ถ๋ฅผ ํ
์คํธ
/** ์ด์ ํ
์คํธ ์ค์ **/
it('์ฌ๋ฐ๋ฅด์ง ์์ ๋๊ตฌ๋ฅผ ์ง์ ํ๋ฉด ์์ธ๋ฅผ ๋์ง๋ค', () => {
var badTool = 'badTool';
expect(function shouldThrow() {
var sandbox = new Conference.WidgetSandbox('tool1', badTool, widgetFcnSpy);
}).toThrowError(Conference.WidgetSandbox.messages.unknownTool + badTool);
});
it('๋๊ตฌ ๋ชจ๋ ํจ์๋ฅผ sandbox์์ ์คํํ๋ค', () => {
spyOn(Conference.WidgetTools, 'tool1');
spyOn(Conference.WidgetTools, 'tool2');
var sandbox = new Conference.WidgetSandbox('tool1', 'tool2', widgetFcnSpy);
expect(Conference.WidgetTools.tool1).toHaveBeenCalledWith(sandbox);
expect(Conference.WidgetTools.tool2).toHaveBeenCalledWith(sandbox);
});
});
});
});
์ด์ ๋ค์์ฒ๋ผ WidgetSandbox ์์ฑ์ ํจ์๋ฅผ ๊ณ ์น๋ฉด ๊ฐ๋ณ ์ธ์๋ก ๋๊ตฌ๋ช ์ ๋๊ฒจ๋ ๋ฌธ์ ์์ด ์ฒ๋ฆฌํ ์ ์๋ค.
var Conference = Conference || {};
Conference.WidgetSandbox = function() {
'use strict';
// Conference.WidgetSandbox(...)๋ฅผ new๋ก ์คํํ๋์ง ๋ณด์ฅํ๋ค.
if (!(this instanceof Conference.WidgetSandbox)) {
throw new Error(Conference.WidgetSandbox.messages.mustBeCalledWithNew);
}
var widgetFunction;
var toolsToLoad = [];
var argsArray;
// arguments์์ ์ง์ง ๋ฐฐ์ด์ ์ถ์ถํ๋ค.
argsArray = Array.prototype.slice.call(arguments);
// ๋ฐฐ์ด ๋ง์ง๋ง ์์๋ widgetFunction์ผ ๊ฒ์ด๋ค. ๋ฝ์๋ธ๋ค.
widgetFunction = argsArray.pop();
if (typeof widgetFunction !== 'function') {
throw new Error(Conference.WidgetSandbox.messages.fcnMustBeProvided);
}
toolsToLoad = (argsArray[0] instanceof Array) ? argsArray[0] : argsArray;
toolsToLoad.forEach(function loadTool(toolName) {
if (!Conference.WidgetTools.hasOwnProperty(toolName)) {
throw new Error(Conference.WidgetSandbox.messages.unKnownTool + toolName);
}
Conference.WidgetTools[toolName](this);
}, this); // ์ฝ๋ฐฑ ๋ด์์ this๊ฐ sandbox ์ธ์คํด์ค ๋ฅผ ๊ฐ๋ฆฌํค๋๋ก ๋ณด์ฅํ๋ค.
var widget = widgetFunction(this);
};
/** ์ด์ ์ฝ๋ ์ค์ **/
๐ ์๋๋ฐ์ค ๋๊ตฌ ์์ฑ๊ณผ ํ ์คํ โ
WidgetSandbox ์์ฒด๋ ์ฌ์ค ๋ณ๋ก ํจ์ฉ์ฑ์ด ์๋ค. ์์ ฏ ์ธ์คํด์ค๋ ๊นจ๋ํ๊ฒ ๋ผ์ด ๋์์ง๋ง, ์์ ฏ๋ค์ด ๋ญ๊ฐ ์ผ์ ํ๋ ๋ฐ ํ์ํ ๋๊ตฌ๊ฐ ์ ํ ์๋ค.
๋์๋ณด๋์์ ๋ด์ผ ํ ๋ฐ์ดํฐ ์ค ์ฝํผ๋ฐ์ค ๋ฑ๋ก์ ๋ช ๋จ์ ์๋ง ๋ชจ๋ ๋ด๋น์์๊ฒ ๊ณตํต์ผ ๊ฒ์ด๋ค. ์นํ์ ๋ฑ๋ก์ ์ฑ๋ช ์ ์์ ฏ์ ๋ณด์ฌ์ค ๋๊ตฌ ๊ฐ๋ฐ์ ์ฐฉ์ํ๋ค.
์ฐธ๊ฐ์ ๋ฑ๋ก ์ฒ๋ฆฌ๋ฅผ ๊ด์ฅํ๋ attendeeWebApi ๊ฐ์ฒด๋ ์ด๋ฏธ ๋ง๋ค์ด์ง ์ํ์ธ๋ฐ, ๊ทธ์ค getAll() ๋ฉ์๋๋ attendee ๊ฐ์ฒด์ ๋ฐฐ์ด๋ก ๊ท๊ฒฐํ๋ ํ๋ผ๋ฏธ์ค๋ฅผ ๋ฐํํ๋ค. ์นํ์ attendeeNames๋ผ๋ ๋๊ตฌ๋ฅผ ๋ง๋ค์ด์ attendeeWebApi์ ํผ์ฌ๋๋ก ์ผ์ ํ์ํ ๊ธฐ๋ฅ์ ํ์ํ๊ธฐ๋ก ํ๋ค.
attendeeNames ๋๊ตฌ์ ๋จ์ ํ
์คํธ๋ฅผ ์์ฑํ์
describe('Conference.WidgetTools.attendeeNames', () => {
'use strict';
var attendeeWebApi;
var sandbox;
beforeEach(() => {
attendeeWebApi = Conference.attendeeWebApi();
// post ๋ฉ์๋๋ ํธ์ถ๋๋ฉด ์ ๋๋ค.
// ๊ทธ๋๋ ํน์ ๋ชจ๋ฅด๋ ์คํ์ด๋ฅผ ์ฌ์ด๋์ด ํ์ธํ๋ค.
spyOn(attendeeWebApi, 'post');
// attendeeNames๋ฅผ ๋จ์ ํ
์คํธํ๊ณ ์ sandbox๋ ๋น ๊ฐ์ฒด๋ก ์ง์ ํ๋ค.
sandbox = {};
});
afterEach(() => {
// ํ
์คํธํ ๋๋ง๋ค post๊ฐ ํธ์ถ๋์ง ์์๋์ง ํ์ธํ๋ค.
expect(attendeeWebApi.post).not.toHaveBeenCalled();
});
it('์ฃผ์ด์ง sandbox ๊ฐ์ฒด์ ์์ ์ ์ถ๊ฐํ๋ค', () => {
Conference.WidgetTools.attendeeNames(sandbox, attendeeWebApi);
expect(sandbox.attendeeNames).not.toBeUndefined();
});
describe('attendeeNames.getAll()', () => {
var attendees;
var attendeeNames;
beforeEach(() => {
Conference.WidgetTools.attendeeNames(sandbox, attendeeWebApi);
// ํ
์คํธ ์ฐธ๊ฐ์ ๋ฐฐ์ด์ ์ฑ์๋ฃ๋๋ค.
attendees = [
Conference.attendee('ํํฌ', '๊น');
Conference.attendee('์ค์ง', '๊น');
Conference.attendee('์ ์ค', '์ต');
];
// ํ
์คํธ ์ฐธ๊ฐ์ ๋ฐฐ์ด์์ ์ด๋ฆ์ ์ถ์ถํ๋ค.
attendeeNames = [];
attendees.forEach(function getNames(attendee) {
attendeeNames.push(attendee.getFullName());
});
});
it('์ฐธ๊ฐ์๊ฐ ์์ ๊ฒฝ์ฐ ๋น ๋ฐฐ์ด๋ก ๊ท๊ฒฐํ๋ค', (done) => {
spyOn(attendeeWebApi, 'getAll').and.returnValue(
new Promise(function(resolve, reject) {
resolve([]);
}),
);
sandbox.attendeeNames.getAll().then(function resolved(names) {
expect(names).toEqual([]);
done();
}, function rejected(reason) {
expect('์คํจํจ').toBe(false);
done();
});
});
it('์ฐธ๊ฐ์๊ฐ ์์ ๊ฒฝ์ฐ ํด๋น ์ด๋ฆ์ผ๋ก ๊ท๊ฒฐํ๋ค', (done) => {
spyOn(attendeeWebApi, 'getAll').and.returnValue(
new Promise(function(resolve, reject) {
resolve(attendees);
}),
);
sandbox.attendeeNames.getAll().then(function resolved(names) {
expect(names).toEqual(attendeeNames);
done();
}, function rejected(reason) {
expect('์คํจํจ').toBe(false);
done();
});
});
it('์ด๋ค ์ฌ์ ๋ก ์ธํด ๋ฒ๋ ค์ง๋ค', (done) => {
var rejectionReason = '๋ฒ๋ฆผ๋ฐ๋ ์ด์ ';
spyOn(attendeeWebApi, 'getAll').and.returnValue(
new Promise(function(resolve, reject) {
reject(rejectionReason);
}),
);
sandbox.attendeeNames.getAll().then(function resolved(names) {
expect('๊ท๊ฒฐ๋จ').toBe(false);
done();
}, function rejected(reason) {
expect(reason).toBe(rejectionReason);
done();
});
});
});
});
attendeeWebApi.getAll()๊ฐ ๋ฐํํ ํ๋ผ๋ฏธ์ค๊ฐ attendeeNames.getAll() ๋ฉ์๋๋ฅผ ํตํด ์ ๋๋ก ํ๋ฌ๊ฐ๋์ง ์ฒดํฌํ๋ฉด ๋๋ค. ๋ํ, attendeeNames.getAll()์ด ๊ฐ attendee ๊ฐ์ฒด์ ์ ๋ถ๊ฐ ์๋, ์ฐธ๊ฐ์ ์ฑ๋ช
๋ง ์ถ์ถํด์ ์ ์ ํ ๋ฐํํ๋์ง ๊ฒ์ฌํ๋ค.
๋ค์์ attendeeNames ๋๊ตฌ์ ๊ตฌํ๋ถ์ด๋ค.
var Conference = Conference || {};
Conference.WidgetTools = Conference.WidgetTools || {};
Conference.WidgetTools.attendeeNames = function(sandbox, injectedAttendeeWebApi) {
'use strict';
// attendeeWebApi๋ฅผ ์ ํ์ ์ผ๋ก ์ฃผ์
ํ ์ ์๊ฒ ์ฝ๋ฉํ๋ค. ๋จ์ ํ
์คํธํ ๋ ์ ์ฉํ๋ค.
var attendeeWebApi = injectedAttendeeWebApi || Conference.attendeeWebApi();
sandbox.attendeeNames = {
// ์ฐธ๊ฐ์ ์ด๋ฆ ๋ฐฐ์ด๋ก ๊ท๊ฒฐํ๋ ํ๋ผ๋ฏธ์ค๋ฅผ ๋ฐํํ๋ค.
getAll: function getAll() {
return attendeeWebApi.getAll().then(function extractNames(attendees) {
// ๊ฐ ์ฐธ๊ฐ์์ ์ ์ฒด ์ฑ๋ช
๋ง ์ถ์ถํ์ฌ ๋ฐํํ๋ค.
var names = [];
attendees.forEach(function addName(attendee) {
names.push(attendee.getFullName());
});
return names;
});
}
};
};
๐ ์๋๋ฐ์ค์์ ์ธ ํจ์ ๋ง๋ค๊ธฐโ
์๋๋ฐ์ค์ ๋๊ณ ์ฌ์ฉํ ๋ชจ๋์ ์์ฑ๊ณผ ํ ์คํธ๋ ๋น๊ต์ ๊ฐ๋จํ๋ค. ์๋๋ฐ์ค ํจํด์์๋ ๋ถ๋ฆฌํ ๋ชจ๋์ ์ค์ง ์๋๋ฐ์ค ์ธ์คํด์ค์๋ง ์์กดํ๋ฉฐ ์ด ์ธ์คํด์ค๋ ๋ฐ๋์ ๋ชจ๋์ ์ฃผ์ ํ๋๋ก ๋ช ์๋์ด ์๋ค. ์์กด์ฑ์ ์ฃผ์ ํ๋ฉด ์๋ฐ์คํฌ๋ฆฝํธ ์ฝ๋์ ํ ์คํธ์ฑ๊ณผ ๋ฏฟ์์ฑ์ด ์ข์์ง๋ค.
์นํ์ด attendeeNames ๋๊ตฌ ๊ฐ๋ฐ์ ๋ชฐ๋ํ ์ฆ์, ์ฌ๋ฟ์ ์์ ฏ์์ ๋ธ๋ผ์ฐ์ ๋ฌธ์ ๊ฐ์ฒด ๋ชจ๋ธ(DOM)์ ์ฐ๋ํ ๋ ์ธ dom ๋๊ตฌ๋ฅผ ๊ฐ๋ฐ ์ค์ด๋ค. ์นํ์ด ๊ฐ๋ฐํ attendeeNames์ ์ฌ๋ฟ์ด ์์ฑํ dom, ๋ ๋๊ตฌ๋ฅผ ํฉํ๋ฉด ๋น๋ก์ ์ฐธ๊ฐ์ ์ฑ๋ช
์ ๋ณด์ฌ์ฃผ๋ ์์ ฏ์ด ์์ฑ๋๋ค. ๋ค์ ์์ ๋ ์์ ฏ ๋จ์ ํ
์คํธ ์ผ๋ถ๋ฅผ ๋ฐ์ทํ ์ฝ๋๋ค.
describe('Conference.Widgets.attendeeNamesWidget(sandbox)', () => {
'use strict';
var sandbox;
beforeEach(() => {
sandbox = {};
});
it('dom ๋๊ตฌ๋ฅผ ์ฌ์ฉํ ์ ์๋ ๊ฒฝ์ฐ ์๋ฌ๋ฅผ ๋์ง๋ค', () => {
expect(function shouldThrow() {
Conference.Widgets.attendeeNamesWidget(sandbox);
}).toThrowError(Conference.Widgets.messages.missingTool + 'dom');
});
it('attendeeNames ๋๊ตฌ๋ฅผ ์ฌ์ฉํ ์ ์๋ ๊ฒฝ์ฐ ์๋ฌ๋ฅผ ๋์ง๋ค', () => {
expect(function shouldThrow() {
sandbox.dom = {};
Conference.Widgets.attendeeNamesWidget(sandbox);
}).toThrowError(Conference.Widgets.messages.missingTool + 'attendeeNames');
});
// attendeeNamesWidget์ด ์ ๋๋ก ์๋ํ๋์ง ํ์ธํ๋ ๋ค๋ฅธ ํ
์คํธ
});
์๋๋ฐ์ค ๊ฐ์ฒด๋ก ์์ ฏ ์ฌ์ฉ ๋ถ๋ถ์ ํ
์คํธํ๋ ์ฝ๋ ์ธ์, ๋ค๋ฅธ ์์ ฏ ๊ธฐ๋ฅ์ ํ์ธํ๋ ํ
์คํธ๋ ๋ณ๋ก ์๋ก์ธ ๊ฒ ์๋ค. ํ
์คํธํ ๋ ๊ผญ WidgetSandbox ์ธ์คํด์ค๋ฅผ ์จ์ผ ํ๋ ๊ฑด ์๋๋ค. ์์ ฏ์ ๊ดํ ํ ์๋๋ฐ์ค ๊ธฐ๋ฅ์ ๋๊ตฌ๋ฅผ ์ฃผ๋ ์ผ์ด ์ ๋ถ ๋ผ ๊ฐ์ฒด ๋ฆฌํฐ๋ด ์ ๋๋ฉด ํ
์คํธ ์ฉ๋๋ก ์ถฉ๋ถํ๋ค.
var Conference = Conference || {};
Conference.Widgets = Conference.Widgets || {};
Conference.Widgets.attendeeNamesWidget = function(sandbox) {
'use strict';
// ํด๋น ๋๊ตฌ๋ฅผ ์ฌ์ฉํ ์ ์์ผ๋ฉด ์ฆ์ ์คํจ ์ฒ๋ฆฌํ๋ค.
if (!sandbox.dom) {
throw new Error(Conference.Widgets.messages.missingTool + 'dom');
}
if (!sandbox.attendeeNames) {
throw new Error(Conference.Widgets.messages.missingTool + 'attendeeNames');
}
// attendeeNames๋ฅผ ์กฐํํ์ฌ ๋์๋ณด๋์ ์ถ๊ฐํ๋ค.
sandbox.attendeeNames.getAll().then(function resolved(names) {
// sandbox.dom์ผ๋ก ์ด๋ฆ ๋ชฉ๋ก์ ํ์ํ๋ค.
}, function rejected(reason) {
// sandbox.dom์ผ๋ก ์์ ฏ ๋์ ์๋ฌ ๋ฉ์์ง๋ฅผ ๋ํ๋ธ๋ค.
});
};
Conference.Widgets.messages = {
missingTool: '๋๋ฝ๋ ๋๊ตฌ: ',
};
๐ ์ ๋ฆฌํ๊ธฐโ
์๋๋ฐ์ค ํจํด์ ๋ชจ๋ ๊ฐ ๊ฒฐํฉ๋๋ฅผ ๋ฎ์ถ๊ณ ์์กด์ฑ์ ์๊ฒฉํ๊ฒ ๋ค์ค๋ฆฌ๋ ๊ธฐ๋ฒ์ด๋ค.
์๋๋ฐ์ค ํจํด์ ๊ตฌํํ ์ฝ๋๋ ๋จ์ ํ ์คํธ๋ก ๋ค์ ํญ๋ชฉ์ ๊ผญ ํ์ธํด์ผ ํ๋ค.
- ์๋๋ฐ์ค ์์ฑ์ ํจ์์ ์์ ฏ ๋ชจ๋ ํจ์๋ฅผ ์ ๋ฌํ๋ค.
- ๋๊ตฌ๋ ์๋๋ฐ์ค ์์ฑ์ ํจ์์ ๋ฐฐ์ด ๋๋ ๊ฐ๋ณ ์ธ์ ํํ๋ก ๋๊ธด๋ค.
- ์๋๋ฐ์ค์์ ์ฌ์ฉํ๊ธฐ๋ก ์ง์ ํ ๋๊ตฌ๊ฐ ์ ํจํ๋ค.
- ์๋๋ฐ์ค ์์์ ์คํํ ์์ ฏ์ด ์์ฒญํ ๋๊ตฌ๋ ์๋๋ฐ์ค๊ฐ ์ ๊ณตํ๋ค.