๐ 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: '๋๋ฝ๋ ๋๊ตฌ: ',
};
๐ ์ ๋ฆฌํ๊ธฐโ
์๋๋ฐ์ค ํจํด์ ๋ชจ๋ ๊ฐ ๊ฒฐํฉ๋๋ฅผ ๋ฎ์ถ๊ณ ์์กด์ฑ์ ์๊ฒฉํ๊ฒ ๋ค์ค๋ฆฌ๋ ๊ธฐ๋ฒ์ด๋ค.
์๋๋ฐ์ค ํจํด์ ๊ตฌํํ ์ฝ๋๋ ๋จ์ ํ ์คํธ๋ก ๋ค์ ํญ๋ชฉ์ ๊ผญ ํ์ธํด์ผ ํ๋ค.
- ์๋๋ฐ์ค ์์ฑ์ ํจ์์ ์์ ฏ ๋ชจ๋ ํจ์๋ฅผ ์ ๋ฌํ๋ค.
- ๋๊ตฌ๋ ์๋๋ฐ์ค ์์ฑ์ ํจ์์ ๋ฐฐ์ด ๋๋ ๊ฐ๋ณ ์ธ์ ํํ๋ก ๋๊ธด๋ค.
- ์๋๋ฐ์ค์์ ์ฌ์ฉํ๊ธฐ๋ก ์ง์ ํ ๋๊ตฌ๊ฐ ์ ํจํ๋ค.
- ์๋๋ฐ์ค ์์์ ์คํํ ์์ ฏ์ด ์์ฒญํ ๋๊ตฌ๋ ์๋๋ฐ์ค๊ฐ ์ ๊ณตํ๋ค.