Skip to content

Commit 01ac1c5

Browse files
authored
Merge pull request #31 from streamdevs/5-disco-mode
5 disco mode
2 parents 6b3c0df + ac9c5cd commit 01ac1c5

6 files changed

Lines changed: 175 additions & 0 deletions

File tree

packages/lul/src/services/light/FakeLightService.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ export class FakeLightService implements LightService {
44
public turnOff = jest.fn();
55
public turnOn = jest.fn();
66
public changeColor = jest.fn();
7+
public disco = jest.fn();
78
}

packages/lul/src/services/light/LifxLightService.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,37 @@ interface ChangeColorOptions {
99
duration?: number;
1010
}
1111

12+
interface DiscoOptions {
13+
color: string;
14+
cycles: number;
15+
period: number;
16+
initialColor?: string;
17+
}
18+
1219
export class LifxLightService implements LightService {
1320
public constructor(
1421
private driver: HttpDriver = DriverFactory.buildHttpDriver()
1522
) {}
1623

24+
public async disco(light: Light, options: DiscoOptions): Promise<void> {
25+
const { color, cycles, period, initialColor } = options;
26+
27+
await this.driver.post(
28+
`https://api.lifx.com/v1/lights/id:${light.id}/effects/breathe`,
29+
{
30+
payload: {
31+
color,
32+
cycles,
33+
period,
34+
...(initialColor && { from_color: initialColor }),
35+
},
36+
headers: {
37+
Authorization: `Bearer ${getConfiguration().lifx.accessToken}`,
38+
},
39+
}
40+
);
41+
}
42+
1743
public async changeColor(
1844
light: Light,
1945
options: ChangeColorOptions

packages/lul/src/services/light/LightService.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,13 @@ export interface LightService {
44
turnOn(light: Light): Promise<void>;
55
turnOff(light: Light): Promise<void>;
66
changeColor(light: Light, options: any): Promise<void>;
7+
disco(
8+
light: Light,
9+
options: {
10+
color: string;
11+
cycles: number;
12+
period: number;
13+
initialColor?: string;
14+
}
15+
): Promise<void>;
716
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import stc from "string-to-color";
2+
import { Reward, Light } from "../../entities";
3+
import { LifxLightService, LightService } from "../../services";
4+
import { RewardActionUseCase } from "./RewardActionUseCase";
5+
6+
type PerformOptions = {
7+
reward: Reward;
8+
lights: Light[];
9+
};
10+
11+
export class Disco implements RewardActionUseCase {
12+
public constructor(
13+
private lightService: LightService = new LifxLightService()
14+
) {}
15+
16+
public async perform({ reward, lights }: PerformOptions): Promise<void> {
17+
const color = stc(reward.message);
18+
const initialColor = stc(reward.date);
19+
20+
await Promise.all(
21+
lights.map((light) =>
22+
this.lightService.disco(light, {
23+
color,
24+
initialColor,
25+
cycles: 5,
26+
period: 20,
27+
})
28+
)
29+
);
30+
}
31+
}
32+
33+
export default Disco;

packages/lul/tests/services/light/LifxLightService.spec.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,4 +137,61 @@ describe("LifxLightService", () => {
137137
).rejects.toThrow(new Error("Boom!"));
138138
});
139139
});
140+
141+
describe("#disco", () => {
142+
it("calls the LIFX API with the color, cycles, period and lights", async () => {
143+
const driver = new FakeHttpDriver();
144+
const subject = new LifxLightService(driver);
145+
const light = LightBuilder.build({ service: "LIFX" });
146+
147+
await subject.disco(light, { color: "red", cycles: 5, period: 5 });
148+
149+
expect(driver.post).toHaveBeenCalledWith(
150+
`https://api.lifx.com/v1/lights/id:${light.id}/effects/breathe`,
151+
{
152+
payload: { color: "red", cycles: 5, period: 5 },
153+
headers: { Authorization: "Bearer fake-lifx-token" },
154+
}
155+
);
156+
});
157+
158+
it("calls the LIFX API with the initialColor, color, cycles, period and lights", async () => {
159+
const driver = new FakeHttpDriver();
160+
const subject = new LifxLightService(driver);
161+
const light = LightBuilder.build({ service: "LIFX" });
162+
163+
await subject.disco(light, {
164+
color: "red",
165+
cycles: 5,
166+
period: 5,
167+
initialColor: "blue",
168+
});
169+
170+
expect(driver.post).toHaveBeenCalledWith(
171+
`https://api.lifx.com/v1/lights/id:${light.id}/effects/breathe`,
172+
{
173+
payload: { color: "red", cycles: 5, period: 5, from_color: "blue" },
174+
headers: { Authorization: "Bearer fake-lifx-token" },
175+
}
176+
);
177+
});
178+
179+
it("throws the error if the driver fails", async () => {
180+
const driver = new FakeHttpDriver();
181+
driver.post.mockImplementation(() => {
182+
throw new Error("Boom!");
183+
});
184+
const light = LightBuilder.build({ service: "LIFX" });
185+
const subject = new LifxLightService(driver);
186+
187+
await expect(
188+
subject.disco(light, {
189+
color: "red",
190+
cycles: 5,
191+
period: 5,
192+
initialColor: "blue",
193+
})
194+
).rejects.toThrow(new Error("Boom!"));
195+
});
196+
});
140197
});
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import stc from "string-to-color";
2+
import { FakeLightService } from "../../../src";
3+
import { Disco } from "../../../src/useCases/rewards/Disco";
4+
import { LightBuilder } from "../../builders/LightBuilder";
5+
import { RewardBuilder } from "../../builders/RewardBuilder";
6+
7+
jest.mock("string-to-color", () => jest.fn(() => "#fefefe"));
8+
9+
describe("Disco", () => {
10+
describe("#perform", () => {
11+
it("uses the reward message to generate the color for the disco mode", async () => {
12+
const lightService = new FakeLightService();
13+
const subject = new Disco(lightService);
14+
const reward = RewardBuilder.build();
15+
const lights = LightBuilder.buildList(1);
16+
17+
await subject.perform({ reward, lights });
18+
19+
expect(stc).toHaveBeenCalledWith(reward.message);
20+
});
21+
22+
it("uses the reward date to generate the initialColor for the disco mode", async () => {
23+
const lightService = new FakeLightService();
24+
const subject = new Disco(lightService);
25+
const reward = RewardBuilder.build();
26+
const lights = LightBuilder.buildList(1);
27+
28+
await subject.perform({ reward, lights });
29+
30+
expect(stc).toHaveBeenCalledWith(reward.date);
31+
});
32+
33+
it("uses light service to start the disco mode", async () => {
34+
const lightService = new FakeLightService();
35+
const subject = new Disco(lightService);
36+
const reward = RewardBuilder.build();
37+
const lights = LightBuilder.buildList(1);
38+
39+
await subject.perform({ reward, lights });
40+
41+
expect(lightService.disco).toHaveBeenCalledWith(lights[0], {
42+
color: "#fefefe",
43+
initialColor: "#fefefe",
44+
cycles: 5,
45+
period: 20,
46+
});
47+
});
48+
});
49+
});

0 commit comments

Comments
 (0)