@rtsdk/topia 0.0.7 → 0.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/dist/__mocks__/assets.js +241 -0
  2. package/dist/__mocks__/index.js +4 -0
  3. package/dist/__mocks__/scenes.js +104 -0
  4. package/dist/__mocks__/visitors.js +83 -0
  5. package/dist/__mocks__/worlds.js +51 -0
  6. package/dist/controllers/Asset.js +62 -0
  7. package/dist/controllers/DroppedAsset.js +150 -0
  8. package/dist/controllers/Scene.js +22 -0
  9. package/dist/controllers/Visitor.js +70 -0
  10. package/dist/controllers/World.js +121 -55
  11. package/dist/controllers/__tests__/asset.test.js +14 -0
  12. package/dist/controllers/__tests__/droppedAsset.test.js +109 -0
  13. package/dist/controllers/__tests__/scene.test.js +14 -0
  14. package/dist/controllers/__tests__/visitor.test.js +12 -0
  15. package/dist/controllers/__tests__/world.test.js +50 -0
  16. package/dist/controllers/index.js +5 -0
  17. package/dist/index.js +455 -83
  18. package/dist/interfaces/DroppedAssetInterfaces.js +1 -0
  19. package/dist/interfaces/WorldInterfaces.js +1 -0
  20. package/dist/interfaces/index.js +2 -0
  21. package/dist/types/DroppedAssetType.js +1 -0
  22. package/dist/types/DroppedAssetTypes.js +12 -0
  23. package/dist/types/VisitorType.js +1 -0
  24. package/dist/types/VisitorTypes.js +1 -0
  25. package/dist/types/Visitors.js +1 -0
  26. package/dist/types/index.js +2 -0
  27. package/dist/utils/__tests__/scatterVisitors.test.js +11 -0
  28. package/dist/utils/createDroppedAsset.js +72 -0
  29. package/dist/utils/createVisitor.js +3 -0
  30. package/dist/utils/getErrorMessage.js +5 -0
  31. package/dist/utils/index.js +4 -0
  32. package/dist/utils/publicAPI.js +11 -0
  33. package/dist/utils/scatterVisitors.js +5 -0
  34. package/package.json +6 -3
  35. package/dist/index.test.js +0 -19
@@ -0,0 +1,150 @@
1
+ import { getErrorMessage, publicAPI } from "utils";
2
+ import Asset from "./Asset";
3
+ export class DroppedAsset extends Asset {
4
+ apiKey;
5
+ text;
6
+ urlSlug;
7
+ // TODO: should we explicitly declare each or simplify with Object.assign for all optional properties? (kinda breaks the ts rules but looks so much nicer!)
8
+ constructor(apiKey, args, text, urlSlug) {
9
+ super(args.addedOn, apiKey, args.assetName, args.creatorTags, args.id, args.isPublic, args.kitId, args.layer0, args.layer1, args.library, args.originalAssetId, args.originalKit, args.ownerId, args.ownerName, args.platformAsset, args.purchased, args.purchaseDate, args.purchasedFrom, args.specialType, args.transactionId, args.type, urlSlug);
10
+ this.apiKey = apiKey;
11
+ this.text = text;
12
+ this.urlSlug = urlSlug;
13
+ Object.assign(this, args);
14
+ this.updateCustomText;
15
+ }
16
+ // get dropped asset
17
+ fetchDroppedAssetById() {
18
+ return new Promise((resolve, reject) => {
19
+ publicAPI(this.apiKey)
20
+ .get(`/world/${this.urlSlug}/assets/${this.id}`)
21
+ .then((response) => {
22
+ Object.assign(this, response.data);
23
+ resolve("Success!");
24
+ })
25
+ .catch((error) => {
26
+ reject(new Error(getErrorMessage(error)));
27
+ });
28
+ });
29
+ }
30
+ // delete dropped asset
31
+ deleteDroppedAsset() {
32
+ return new Promise((resolve, reject) => {
33
+ publicAPI(this.apiKey)
34
+ .delete(`/world/${this.urlSlug}/assets/${this.id}`)
35
+ .then(() => {
36
+ resolve("Success!");
37
+ })
38
+ .catch((error) => {
39
+ reject(new Error(getErrorMessage(error)));
40
+ });
41
+ });
42
+ }
43
+ // update dropped assets
44
+ #updateDroppedAsset = (payload, updateType) => {
45
+ console.log("apiKey", this.apiKey);
46
+ return new Promise((resolve, reject) => {
47
+ publicAPI(this.apiKey)
48
+ .put(`/world/${this.urlSlug}/assets/${this.id}/${updateType}`, {
49
+ ...payload,
50
+ })
51
+ .then(() => {
52
+ resolve("Success!");
53
+ })
54
+ .catch((error) => {
55
+ reject(new Error(getErrorMessage(error)));
56
+ });
57
+ });
58
+ };
59
+ updateBroadcast({ assetBroadcast, assetBroadcastAll, broadcasterEmail }) {
60
+ return new Promise((resolve, reject) => {
61
+ return this.#updateDroppedAsset({ assetBroadcast, assetBroadcastAll, broadcasterEmail }, "set-asset-broadcast")
62
+ .then(resolve)
63
+ .catch((error) => {
64
+ reject(new Error(getErrorMessage(error)));
65
+ });
66
+ });
67
+ }
68
+ updateClickType({ clickType, clickableLink, clickableLinkTitle, portalName, position, }) {
69
+ return new Promise((resolve, reject) => {
70
+ return this.#updateDroppedAsset({ clickType, clickableLink, clickableLinkTitle, portalName, position }, "change-click-type")
71
+ .then(resolve)
72
+ .catch((error) => {
73
+ reject(new Error(getErrorMessage(error)));
74
+ });
75
+ });
76
+ }
77
+ updateCustomText(style, text) {
78
+ return new Promise((resolve, reject) => {
79
+ return this.#updateDroppedAsset({ style, text }, "set-custom-text")
80
+ .then(resolve)
81
+ .catch((error) => {
82
+ reject(new Error(getErrorMessage(error)));
83
+ });
84
+ });
85
+ }
86
+ updateMediaType({ audioRadius, audioVolume, isVideo, mediaLink, mediaName, mediaType, portalName, syncUserMedia, }) {
87
+ return new Promise((resolve, reject) => {
88
+ return this.#updateDroppedAsset({ audioRadius, audioVolume, isVideo, mediaLink, mediaName, mediaType, portalName, syncUserMedia }, "change-media-type")
89
+ .then(resolve)
90
+ .catch((error) => {
91
+ reject(new Error(getErrorMessage(error)));
92
+ });
93
+ });
94
+ }
95
+ updateMuteZone(isMutezone) {
96
+ return new Promise((resolve, reject) => {
97
+ return this.#updateDroppedAsset({ isMutezone }, "set-mute-zone")
98
+ .then(resolve)
99
+ .catch((error) => {
100
+ reject(new Error(getErrorMessage(error)));
101
+ });
102
+ });
103
+ }
104
+ updatePosition(x, y) {
105
+ return new Promise((resolve, reject) => {
106
+ return this.#updateDroppedAsset({ x, y }, "set-position")
107
+ .then(resolve)
108
+ .catch((error) => {
109
+ reject(new Error(getErrorMessage(error)));
110
+ });
111
+ });
112
+ }
113
+ updatePrivateZone({ isPrivateZone, isPrivateZoneChatDisabled, privateZoneUserCap, }) {
114
+ return new Promise((resolve, reject) => {
115
+ return this.#updateDroppedAsset({ isPrivateZone, isPrivateZoneChatDisabled, privateZoneUserCap }, "set-private-zone")
116
+ .then(resolve)
117
+ .catch((error) => {
118
+ reject(new Error(getErrorMessage(error)));
119
+ });
120
+ });
121
+ }
122
+ updateScale(assetScale) {
123
+ return new Promise((resolve, reject) => {
124
+ return this.#updateDroppedAsset({ assetScale }, "change-scale")
125
+ .then(resolve)
126
+ .catch((error) => {
127
+ reject(new Error(getErrorMessage(error)));
128
+ });
129
+ });
130
+ }
131
+ updateUploadedMediaSelected(mediaId) {
132
+ return new Promise((resolve, reject) => {
133
+ return this.#updateDroppedAsset({ mediaId }, "change-uploaded-media-selected")
134
+ .then(resolve)
135
+ .catch((error) => {
136
+ reject(new Error(getErrorMessage(error)));
137
+ });
138
+ });
139
+ }
140
+ updateWebImageLayers(bottom, top) {
141
+ return new Promise((resolve, reject) => {
142
+ return this.#updateDroppedAsset({ bottom, top }, "set-webimage-layers")
143
+ .then(resolve)
144
+ .catch((error) => {
145
+ reject(new Error(getErrorMessage(error)));
146
+ });
147
+ });
148
+ }
149
+ }
150
+ export default Asset;
@@ -0,0 +1,22 @@
1
+ import { getErrorMessage, publicAPI } from "utils";
2
+ export class Scene {
3
+ apiKey;
4
+ email;
5
+ constructor(apiKey, email) {
6
+ this.apiKey = apiKey;
7
+ this.email = email;
8
+ }
9
+ fetchScenesByEmail() {
10
+ return new Promise((resolve, reject) => {
11
+ publicAPI(this.apiKey)
12
+ .get(`/scenes/my-scenes?email=${this.email}`)
13
+ .then((response) => {
14
+ resolve(response.data);
15
+ })
16
+ .catch((error) => {
17
+ reject(new Error(getErrorMessage(error)));
18
+ });
19
+ });
20
+ }
21
+ }
22
+ export default Scene;
@@ -0,0 +1,70 @@
1
+ import { getErrorMessage, publicAPI } from "utils";
2
+ export class Visitor {
3
+ apiKey;
4
+ color;
5
+ displayName;
6
+ gestureType;
7
+ hidden;
8
+ isAdmin;
9
+ isBackground;
10
+ isMobile;
11
+ isRecording;
12
+ isRecordingBot;
13
+ lastUpdate;
14
+ moveFrom;
15
+ movedOn;
16
+ moveTo;
17
+ muted;
18
+ performer;
19
+ performerNear;
20
+ playerId;
21
+ shareScreen;
22
+ sitting;
23
+ urlSlug;
24
+ username;
25
+ constructor(apiKey, color = "", displayName, gestureType = 0, hidden = false, isAdmin = false, isBackground = false, isMobile = false, isRecording = false, isRecordingBot = false, lastUpdate = undefined, moveFrom = {}, movedOn = undefined, moveTo = { x: 0, y: 0 }, muted = false, performer = false, performerNear = false, playerId = undefined, shareScreen = false, sitting = false, urlSlug, username = undefined) {
26
+ this.apiKey = apiKey;
27
+ this.color = color;
28
+ this.displayName = displayName;
29
+ this.gestureType = gestureType;
30
+ this.hidden = hidden;
31
+ this.isAdmin = isAdmin;
32
+ this.isBackground = isBackground;
33
+ this.isMobile = isMobile;
34
+ this.isRecording = isRecording;
35
+ this.isRecordingBot = isRecordingBot;
36
+ this.lastUpdate = lastUpdate;
37
+ this.moveFrom = moveFrom;
38
+ this.movedOn = movedOn;
39
+ this.moveTo = moveTo;
40
+ this.muted = muted;
41
+ this.performer = performer;
42
+ this.performerNear = performerNear;
43
+ this.playerId = playerId;
44
+ this.shareScreen = shareScreen;
45
+ this.sitting = sitting;
46
+ this.urlSlug = urlSlug;
47
+ this.username = username;
48
+ this.moveVisitor;
49
+ }
50
+ moveVisitor(shouldTeleportVisitor, x, y) {
51
+ return new Promise((resolve, reject) => {
52
+ publicAPI(this.apiKey)
53
+ .put(`/world/${this.urlSlug}/visitors/${this.playerId}/move`, {
54
+ moveTo: {
55
+ x,
56
+ y,
57
+ },
58
+ teleport: shouldTeleportVisitor,
59
+ })
60
+ .then(() => {
61
+ this.moveTo = { x, y };
62
+ resolve("Success!");
63
+ })
64
+ .catch((error) => {
65
+ reject(new Error(getErrorMessage(error)));
66
+ });
67
+ });
68
+ }
69
+ }
70
+ export default Visitor;
@@ -1,71 +1,137 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- import axios from "axios";
11
- const API_URL = "https://api.topia.io/api";
12
- class World {
1
+ import { createVisitor, getErrorMessage, publicAPI, scatterVisitors } from "utils";
2
+ import { DroppedAsset } from "controllers/DroppedAsset";
3
+ import { Visitor } from "controllers/Visitor";
4
+ export class World {
5
+ #droppedAssetsMap;
6
+ #visitorsMap;
7
+ apiKey;
8
+ background;
9
+ controls;
10
+ created;
11
+ description;
12
+ enforceWhitelistOnLogin;
13
+ forceAuthOnLogin;
14
+ height;
15
+ heroImage;
16
+ mapExists;
17
+ name;
18
+ redirectTo;
19
+ spawnPosition;
20
+ tileBackgroundEverywhere;
21
+ urlSlug;
22
+ useTopiaPassword;
23
+ width;
24
+ get droppedAssets() {
25
+ return this.#droppedAssetsMap;
26
+ }
27
+ get visitors() {
28
+ return this.#visitorsMap;
29
+ }
13
30
  constructor(apiKey, urlSlug) {
14
31
  this.apiKey = apiKey;
15
32
  this.urlSlug = urlSlug;
16
33
  }
34
+ // world details
17
35
  fetchDetails() {
18
- return __awaiter(this, void 0, void 0, function* () {
19
- return new Promise((resolve, reject) => {
20
- axios
21
- .get(`${API_URL}/world/${this.urlSlug}/world-details`, {
22
- headers: { Authorization: this.apiKey },
23
- })
24
- .then((response) => {
25
- console.log("🚀 ~ file: World.ts ~ line 21 ~ World ~ .then ~ response", response);
26
- resolve(response.data);
27
- })
28
- .catch(reject);
36
+ return new Promise((resolve, reject) => {
37
+ publicAPI(this.apiKey)
38
+ .get(`/world/${this.urlSlug}/world-details`)
39
+ .then((response) => {
40
+ Object.assign(this, response.data);
41
+ resolve("Success!");
42
+ })
43
+ .catch((error) => {
44
+ reject(new Error(getErrorMessage(error)));
45
+ });
46
+ });
47
+ }
48
+ updateDetails() {
49
+ return new Promise((resolve, reject) => {
50
+ publicAPI(this.apiKey)
51
+ .get(`/world/${this.urlSlug}/world-details`)
52
+ .then(() => {
53
+ resolve("Success!");
54
+ })
55
+ .catch((error) => {
56
+ reject(new Error(getErrorMessage(error)));
29
57
  });
30
58
  });
31
59
  }
60
+ // visitors
32
61
  fetchVisitors() {
33
- return __awaiter(this, void 0, void 0, function* () {
34
- return new Promise((resolve, reject) => {
35
- axios
36
- .get(`${API_URL}/world/${this.urlSlug}/visitors`, {
37
- headers: { Authorization: this.apiKey },
38
- })
39
- .then((response) => {
40
- console.log("🚀 ~ file: World.ts ~ line 35 ~ World ~ .then ~ response", response);
41
- resolve(response.data);
42
- })
43
- .catch(reject);
62
+ return new Promise((resolve, reject) => {
63
+ publicAPI(this.apiKey)
64
+ .get(`/world/${this.urlSlug}/visitors`)
65
+ .then((response) => {
66
+ // create temp map and then update private property only once
67
+ const tempVisitorsMap = {};
68
+ for (const playerId in response.data) {
69
+ tempVisitorsMap[playerId] = createVisitor(Visitor, this.apiKey, response.data[playerId], this.urlSlug);
70
+ }
71
+ this.#visitorsMap = tempVisitorsMap;
72
+ resolve("Success!");
73
+ })
74
+ .catch((error) => {
75
+ reject(new Error(getErrorMessage(error)));
44
76
  });
45
77
  });
46
78
  }
47
- moveVisitor(visitor) {
48
- return __awaiter(this, void 0, void 0, function* () {
49
- return new Promise((resolve, reject) => {
50
- const requestOptions = {
51
- headers: { Authorization: this.apiKey },
52
- body: {
53
- moveTo: {
54
- x: visitor.coordinates.x,
55
- y: visitor.coordinates.y,
56
- },
57
- teleport: true,
58
- },
59
- };
60
- axios
61
- .put(`${API_URL}/world/${this.urlSlug}/visitors/${visitor.visitorId}/move`, requestOptions)
62
- .then((response) => {
63
- console.log("🚀 ~ file: World.ts ~ line 49 ~ World ~ .then ~ response", response);
64
- resolve(response.data);
65
- })
66
- .catch(reject);
79
+ async currentVisitors() {
80
+ try {
81
+ await this.fetchVisitors();
82
+ return this.visitors;
83
+ }
84
+ catch (error) {
85
+ return error;
86
+ }
87
+ }
88
+ async moveAllVisitors({ shouldFetchVisitors = true, shouldTeleportVisitors = true, scatterVisitorsBy = 0, x, y, }) {
89
+ if (shouldFetchVisitors)
90
+ await this.fetchVisitors();
91
+ const allPromises = [];
92
+ if (!this.visitors)
93
+ return;
94
+ const objectKeys = Object.keys(this.visitors);
95
+ objectKeys.forEach((key) => allPromises.push(this.#visitorsMap[key].moveVisitor(shouldTeleportVisitors, scatterVisitors(x, scatterVisitorsBy), scatterVisitors(y, scatterVisitorsBy))));
96
+ const outcomes = await Promise.allSettled(allPromises);
97
+ return outcomes;
98
+ }
99
+ async moveVisitors(visitorsToMove) {
100
+ const allPromises = [];
101
+ visitorsToMove.forEach((v) => {
102
+ allPromises.push(v.visitorObj.moveVisitor(v.shouldTeleportVisitor, v.x, v.y));
103
+ });
104
+ const outcomes = await Promise.allSettled(allPromises);
105
+ return outcomes;
106
+ }
107
+ // dropped assets
108
+ fetchDroppedAssets() {
109
+ return new Promise((resolve, reject) => {
110
+ publicAPI(this.apiKey)
111
+ .get(`/world/${this.urlSlug}/assets`)
112
+ .then((response) => {
113
+ // create temp map and then update private property only once
114
+ const tempDroppedAssetsMap = {};
115
+ for (const id in response.data) {
116
+ // tempDroppedAssetsMap[id] = createDroppedAsset(this.apiKey, response.data[id], this.urlSlug);
117
+ tempDroppedAssetsMap[id] = new DroppedAsset(this.apiKey, response.data[id], "", this.urlSlug);
118
+ }
119
+ this.#droppedAssetsMap = tempDroppedAssetsMap;
120
+ resolve("Success!");
121
+ })
122
+ .catch((error) => {
123
+ reject(new Error(getErrorMessage(error)));
67
124
  });
68
125
  });
69
126
  }
127
+ async updateCustomTextDroppedAssets(droppedAssetsToUpdate, style) {
128
+ // adds ability to update any styles for specified dropped assets only while preserving text
129
+ const allPromises = [];
130
+ droppedAssetsToUpdate.forEach((a) => {
131
+ allPromises.push(a.updateCustomText(style, a.text));
132
+ });
133
+ const outcomes = await Promise.allSettled(allPromises);
134
+ return outcomes;
135
+ }
70
136
  }
71
- export { World };
137
+ export default World;
@@ -0,0 +1,14 @@
1
+ import { assets } from "../../__mocks__";
2
+ import { Asset } from "..";
3
+ afterEach(() => {
4
+ jest.resetAllMocks();
5
+ });
6
+ describe("Asset Class", () => {
7
+ it("should return an array of assets owned by specific email address", async () => {
8
+ const testAsset = new Asset("", "key");
9
+ testAsset.fetchAssetsByEmail = jest.fn().mockReturnValue(assets);
10
+ const mockAssets = await testAsset.fetchAssetsByEmail("lina@topia.io");
11
+ expect(testAsset.fetchAssetsByEmail).toHaveBeenCalled();
12
+ expect(mockAssets).toBeDefined();
13
+ });
14
+ });
@@ -0,0 +1,109 @@
1
+ import { droppedAssets } from "__mocks__";
2
+ import { DroppedAsset } from "..";
3
+ import { DroppedAssetClickType, DroppedAssetMediaType } from "../../types/DroppedAssetTypes";
4
+ import axios from "axios";
5
+ import MockAdapter from "axios-mock-adapter";
6
+ const BASE_URL = `https://api.topia.io/api/world/magic/assets/${droppedAssets[0].id}`;
7
+ describe("DroppedAsset Class", () => {
8
+ let mock;
9
+ beforeAll(() => {
10
+ mock = new MockAdapter(axios);
11
+ });
12
+ afterEach(() => {
13
+ mock.reset();
14
+ jest.resetAllMocks();
15
+ });
16
+ it("should fetch dropped asset by id", async () => {
17
+ const testDroppedAsset = new DroppedAsset("key", { id: droppedAssets[0].id }, "", "magic");
18
+ testDroppedAsset.fetchDroppedAssetById = jest.fn().mockReturnValue(droppedAssets[0]);
19
+ const mockDroppedAssets = await testDroppedAsset.fetchDroppedAssetById();
20
+ expect(testDroppedAsset.fetchDroppedAssetById).toHaveBeenCalled();
21
+ expect(mockDroppedAssets).toBeDefined();
22
+ });
23
+ it("should update dropped asset broadcast zone", async () => {
24
+ mock.onPut(`${BASE_URL}/set-asset-broadcast`).reply(200, "Success!");
25
+ const testDroppedAsset = new DroppedAsset("key", { id: droppedAssets[0].id }, "", "magic");
26
+ const args = {
27
+ assetBroadcast: true,
28
+ assetBroadcastAll: false,
29
+ broadcasterEmail: "test@test.com",
30
+ };
31
+ await testDroppedAsset.updateBroadcast(args);
32
+ expect(mock.history.put.length).toBe(1);
33
+ });
34
+ it("should update dropped asset click type", async () => {
35
+ mock.onPut(`${BASE_URL}/change-click-type`).reply(200, "Success!");
36
+ const testDroppedAsset = new DroppedAsset("key", { id: droppedAssets[0].id }, "", "magic");
37
+ const args = {
38
+ clickType: DroppedAssetClickType.LINK,
39
+ clickableLink: "www.test.com",
40
+ clickableLinkTitle: "Test",
41
+ portalName: "Test",
42
+ position: {
43
+ x: 0,
44
+ y: 0,
45
+ },
46
+ };
47
+ await testDroppedAsset.updateClickType(args);
48
+ expect(mock.history.put.length).toBe(1);
49
+ });
50
+ it("should update dropped asset custom text", async () => {
51
+ mock.onPut(`${BASE_URL}/set-custom-text`).reply(200, "Success!");
52
+ const testDroppedAsset = new DroppedAsset("key", { id: droppedAssets[0].id }, "", "magic");
53
+ await testDroppedAsset.updateCustomText({ textColor: "#abc123" }, "hello world");
54
+ expect(mock.history.put.length).toBe(1);
55
+ });
56
+ it("should update dropped asset media type", async () => {
57
+ mock.onPut(`${BASE_URL}/change-media-type`).reply(200, "Success!");
58
+ const args = {
59
+ audioRadius: 0,
60
+ audioVolume: -1,
61
+ isVideo: true,
62
+ mediaLink: "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
63
+ mediaName: "string",
64
+ mediaType: DroppedAssetMediaType.LINK,
65
+ portalName: "community",
66
+ syncUserMedia: true,
67
+ };
68
+ const testDroppedAsset = new DroppedAsset("key", { id: droppedAssets[0].id }, "", "magic");
69
+ await testDroppedAsset.updateMediaType(args);
70
+ expect(mock.history.put.length).toBe(1);
71
+ });
72
+ it("should update dropped asset mute zone", async () => {
73
+ mock.onPut(`${BASE_URL}/set-mute-zone`).reply(200, "Success!");
74
+ const testDroppedAsset = new DroppedAsset("key", { id: droppedAssets[0].id }, "", "magic");
75
+ await testDroppedAsset.updateMuteZone(true);
76
+ expect(mock.history.put.length).toBe(1);
77
+ });
78
+ it("should update dropped asset position", async () => {
79
+ mock.onPut(`${BASE_URL}/set-position`).reply(200, "Success!");
80
+ const testDroppedAsset = new DroppedAsset("key", { id: droppedAssets[0].id }, "", "magic");
81
+ await testDroppedAsset.updatePosition(100, 100);
82
+ expect(mock.history.put.length).toBe(1);
83
+ });
84
+ it("should update dropped asset private zone", async () => {
85
+ mock.onPut(`${BASE_URL}/set-private-zone`).reply(200, "Success!");
86
+ const args = { isPrivateZone: true, isPrivateZoneChatDisabled: false, privateZoneUserCap: 10 };
87
+ const testDroppedAsset = new DroppedAsset("key", { id: droppedAssets[0].id }, "", "magic");
88
+ await testDroppedAsset.updatePrivateZone(args);
89
+ expect(mock.history.put.length).toBe(1);
90
+ });
91
+ it("should update dropped asset scale", async () => {
92
+ mock.onPut(`${BASE_URL}/change-scale`).reply(200, "Success!");
93
+ const testDroppedAsset = new DroppedAsset("key", { id: droppedAssets[0].id }, "", "magic");
94
+ await testDroppedAsset.updateScale(75);
95
+ expect(mock.history.put.length).toBe(1);
96
+ });
97
+ it("should update dropped asset uploaded media selected", async () => {
98
+ mock.onPut(`${BASE_URL}/change-uploaded-media-selected`).reply(200, "Success!");
99
+ const testDroppedAsset = new DroppedAsset("key", { id: droppedAssets[0].id }, "", "magic");
100
+ await testDroppedAsset.updateUploadedMediaSelected("abc123");
101
+ expect(mock.history.put.length).toBe(1);
102
+ });
103
+ it("should update dropped asset web image layers", async () => {
104
+ mock.onPut(`${BASE_URL}/set-webimage-layers`).reply(200, "Success!");
105
+ const testDroppedAsset = new DroppedAsset("key", { id: droppedAssets[0].id }, "", "magic");
106
+ await testDroppedAsset.updateWebImageLayers("test", "test");
107
+ expect(mock.history.put.length).toBe(1);
108
+ });
109
+ });
@@ -0,0 +1,14 @@
1
+ import { scenes } from "../../__mocks__";
2
+ import { Scene } from "..";
3
+ afterEach(() => {
4
+ jest.resetAllMocks();
5
+ });
6
+ describe("Scene Class", () => {
7
+ it("should return an array of scenes owned by specific email address", async () => {
8
+ const testScene = await new Scene("key", "lina@topia.io");
9
+ testScene.fetchScenesByEmail = jest.fn().mockReturnValue(scenes);
10
+ const mockScenes = await testScene.fetchScenesByEmail();
11
+ expect(testScene.fetchScenesByEmail).toHaveBeenCalled();
12
+ expect(mockScenes).toBeDefined();
13
+ });
14
+ });
@@ -0,0 +1,12 @@
1
+ import { Visitor } from "controllers";
2
+ import { createVisitor } from "../../utils/createVisitor";
3
+ import { visitor } from "../../__mocks__/visitors";
4
+ afterEach(() => {
5
+ jest.resetAllMocks();
6
+ });
7
+ describe("Visitor Class", () => {
8
+ it("should create an instance of Visitor", async () => {
9
+ const testVisitor = createVisitor(Visitor, "apiKey", visitor, "magic");
10
+ expect(testVisitor.displayName).toEqual("test");
11
+ });
12
+ });
@@ -0,0 +1,50 @@
1
+ import { visitors, worlds } from "../../__mocks__";
2
+ import { Visitor, World } from "../../controllers";
3
+ import axios from "axios";
4
+ import MockAdapter from "axios-mock-adapter";
5
+ import { createVisitor } from "utils";
6
+ const BASE_URL = "https://api.topia.io/api/world/magic";
7
+ describe("World Class", () => {
8
+ let mock;
9
+ beforeAll(() => {
10
+ mock = new MockAdapter(axios);
11
+ });
12
+ afterEach(() => {
13
+ mock.reset();
14
+ jest.resetAllMocks();
15
+ });
16
+ it("should return details of a world", async () => {
17
+ const testWorld = await new World("key", "magic");
18
+ expect(testWorld.urlSlug).toEqual("magic");
19
+ testWorld.fetchDetails = jest.fn().mockReturnValue(worlds[1]);
20
+ const mockDetails = await testWorld.fetchDetails();
21
+ expect(testWorld.fetchDetails).toHaveBeenCalled();
22
+ expect(mockDetails).toBeDefined();
23
+ });
24
+ it("should move all visitors within a world to a single set of coordinates", async () => {
25
+ mock.onGet(`${BASE_URL}/visitors`).reply(200, visitors);
26
+ mock.onPut(`${BASE_URL}/visitors/1/move`).reply(200, "Success!");
27
+ const testWorld = await new World("key", "magic");
28
+ const args = { shouldFetchVisitors: true, shouldTeleportVisitors: true, scatterVisitorsBy: 100, x: 20, y: 40 };
29
+ await testWorld.moveAllVisitors(args);
30
+ expect(mock.history.put.length).toBe(Object.keys(visitors).length);
31
+ });
32
+ it("should return success if world doesn't have visitors", async () => {
33
+ const testWorld = await new World("key", "magic");
34
+ const args = { shouldFetchVisitors: false, scatterVisitorsBy: 100, x: 20, y: 40 };
35
+ await testWorld.moveAllVisitors(args);
36
+ expect(mock.history.put.length).toBe(0);
37
+ });
38
+ it("should move a list of visitors to uniquely specified coordinates", async () => {
39
+ mock.onPut(`${BASE_URL}/visitors/1/move`).reply(200, "Success!");
40
+ const testWorld = await new World("key", "magic");
41
+ const v1 = createVisitor(Visitor, "key", visitors["1"], "magic");
42
+ const v2 = createVisitor(Visitor, "key", visitors["2"], "magic");
43
+ const testVisitors = [
44
+ { visitorObj: v1, shouldTeleportVisitor: true, x: 0, y: 0 },
45
+ { visitorObj: v2, shouldTeleportVisitor: false, x: 100, y: 100 },
46
+ ];
47
+ await testWorld.moveVisitors(testVisitors);
48
+ expect(mock.history.put.length).toBe(2);
49
+ });
50
+ });
@@ -0,0 +1,5 @@
1
+ export { Asset } from "./Asset";
2
+ export { DroppedAsset } from "./DroppedAsset";
3
+ export { Scene } from "./Scene";
4
+ export { Visitor } from "./Visitor";
5
+ export { World } from "./World";