-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathplayer.test.js
234 lines (205 loc) · 8 KB
/
player.test.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
jest.setTimeout(1e4);
const dbus = require('dbus-next');
const Variant = dbus.Variant;
const Player = require('../dist');
const JSBI = require('jsbi');
const DBusError = dbus.DBusError;
const ROOT_IFACE = 'org.mpris.MediaPlayer2';
const PLAYER_IFACE = 'org.mpris.MediaPlayer2.Player';
let lcFirst = (str) => {
return str.charAt(0).toLowerCase() + str.slice(1);
};
var player = Player({
name: 'playertest',
identity: 'Node.js media player',
supportedUriSchemes: ['file'],
supportedMimeTypes: ['audio/mpeg', 'application/ogg'],
supportedInterfaces: ['player']
});
player.on('error', (err) => {
console.log(`got unexpected error:\n${err.stack}`);
});
let bus = dbus.sessionBus();
afterAll(() => {
player._bus.disconnect();
bus.disconnect();
});
test('creating a player exports the root and player interfaces on the bus', async () => {
let dbusObj = await bus.getProxyObject('org.freedesktop.DBus', '/org/freedesktop/DBus');
let dbusIface = dbusObj.getInterface('org.freedesktop.DBus');
let names = await dbusIface.ListNames();
expect(names).toEqual(expect.arrayContaining(['org.mpris.MediaPlayer2.playertest']));
let obj = await bus.getProxyObject('org.mpris.MediaPlayer2.playertest', '/org/mpris/MediaPlayer2');
let expectedInterfaces = [
'org.freedesktop.DBus.Introspectable',
'org.freedesktop.DBus.Properties',
ROOT_IFACE,
PLAYER_IFACE
];
for (let expected of expectedInterfaces) {
expect(obj.getInterface(expected)).toBeDefined();
}
});
test('calling the player methods on the bus emits the signals on the object', async () => {
let obj = await bus.getProxyObject('org.mpris.MediaPlayer2.playertest', '/org/mpris/MediaPlayer2');
let playerIface = obj.getInterface(PLAYER_IFACE);
// simple commands called with no event
let commands = [ 'Play', 'Pause', 'PlayPause', 'Stop', 'Next', 'Previous' ];
for (let cmd of commands) {
let cb = jest.fn();
player.once(cmd.toLowerCase(), cb);
await playerIface[cmd]();
expect(cb).toHaveBeenCalledTimes(1);
expect(cb).toHaveBeenCalledWith();
}
// OpenUri
let cb = jest.fn();
player.once('open', cb);
await playerIface.OpenUri('file://somefile');
expect(cb).toHaveBeenCalledTimes(1);
expect(cb).toHaveBeenCalledWith({ uri: 'file://somefile' });
});
test('getting and setting properties on the player and on the interface should work', async () => {
let obj = await bus.getProxyObject('org.mpris.MediaPlayer2.playertest', '/org/mpris/MediaPlayer2');
let playerIface = obj.getInterface(PLAYER_IFACE);
let props = obj.getInterface('org.freedesktop.DBus.Properties');
let peer = obj.getInterface('org.freedesktop.DBus.Peer');
let cb = jest.fn();
props.on('PropertiesChanged', cb);
// Metadata
player.metadata = {
'xesam:artist': ['Katy Perry'],
'xesam:title': 'Rise'
};
await peer.Ping();
let changed = {
Metadata: new Variant('a{sv}', {
'xesam:artist': new Variant('as', ['Katy Perry']),
'xesam:title': new Variant('s', 'Rise')
})
}
expect(cb).toHaveBeenCalledTimes(1);
expect(cb).toHaveBeenLastCalledWith(PLAYER_IFACE, changed, []);
let gotten = await props.Get(PLAYER_IFACE, 'Metadata');
expect(gotten).toEqual(changed.Metadata);
// setting the metadata again to the same thing should only emit
// PropertiesChanged once
player.metadata = JSON.parse(JSON.stringify(player.metadata));
await peer.Ping();
expect(cb).toHaveBeenCalledTimes(1);
// PlaybackStatus
player.playbackStatus = Player.PLAYBACK_STATUS_PAUSED;
await peer.Ping();
changed = {
PlaybackStatus: new Variant('s', 'Paused')
};
expect(cb).toHaveBeenLastCalledWith(PLAYER_IFACE, changed, []);
gotten = await props.Get(PLAYER_IFACE, 'PlaybackStatus');
expect(gotten).toEqual(new Variant('s', 'Paused'));
// LoopStatus
player.loopStatus = Player.LOOP_STATUS_TRACK;
await peer.Ping();
changed = {
LoopStatus: new Variant('s', 'Track')
};
expect(cb).toHaveBeenLastCalledWith(PLAYER_IFACE, changed, []);
gotten = await props.Get(PLAYER_IFACE, 'LoopStatus');
expect(gotten).toEqual(new Variant('s', 'Track'));
let playerCb = jest.fn(val => {
player.loopStatus = val;
});
player.once('loopStatus', playerCb);
await props.Set(PLAYER_IFACE, 'LoopStatus', new Variant('s', 'Playlist'));
expect(playerCb).toHaveBeenCalledWith('Playlist');
changed = {
LoopStatus: new Variant('s', 'Playlist')
};
expect(cb).toHaveBeenLastCalledWith(PLAYER_IFACE, changed, []);
expect(player.loopStatus).toEqual('Playlist');
// trying to set an invalid loop status should give the client an error and
// leave player loop status unchanged
let invalidSet = props.Set(PLAYER_IFACE, 'LoopStatus', new Variant('s', 'AN_INVALID_STATUS'));
await expect(invalidSet).rejects.toBeInstanceOf(DBusError);
expect(player.loopStatus).toEqual('Playlist');
// The Double Properties
let doubleProps = ['Rate', 'Volume', 'MinimumRate', 'MaximumRate'];
for (let name of doubleProps) {
let playerName = lcFirst(name);
player[playerName] = 0.05;
await peer.Ping();
changed = {};
changed[name] = new Variant('d', 0.05);
expect(cb).toHaveBeenLastCalledWith(PLAYER_IFACE, changed, []);
gotten = await props.Get(PLAYER_IFACE, name);
expect(gotten).toEqual(new Variant('d', player[playerName]));
if (name in ['Rate', 'Volume']) {
// these are settable by the client
let playerCb = jest.fn(val => {
player[playerName] = val;
});
player.once(playerName, playerCb);
await props.Set(PLAYER_IFACE, name, new Variant('d', 0.15));
expect(playerCb).toHaveBeenCalledWith(0.15);
expect(player[playerName]).toEqual(0.15);
changed[name] = new Variant('d', 0.15);
expect(cb).toHaveBeenLastCalledWith(PLAYER_IFACE, changed, []);
}
}
// The Boolean properties
let boolProps = ['CanControl', 'CanPause', 'CanPlay', 'CanSeek', 'CanGoNext',
'CanGoPrevious', 'Shuffle'];
for (let name of boolProps) {
let playerName = lcFirst(name);
let newValue = !player[playerName];
player[playerName] = newValue;
await peer.Ping();
changed = {};
changed[name] = new Variant('b', newValue);
expect(cb).toHaveBeenLastCalledWith(PLAYER_IFACE, changed, []);
gotten = await props.Get(PLAYER_IFACE, name);
expect(gotten).toEqual(new Variant('b', player[playerName]));
if (name === 'Shuffle') {
let nextNewValue = !newValue;
// only this property is writable
let playerCb = jest.fn(val => {
player.shuffle = val;
});
player.once('shuffle', playerCb);
await props.Set(PLAYER_IFACE, name, new Variant('b', nextNewValue));
expect(playerCb).toHaveBeenCalledWith(nextNewValue);
expect(player[playerName]).toEqual(nextNewValue);
await peer.Ping();
}
}
});
test('position specific properties, methods, and signals should work', async () => {
// note: they are responsible for setting the position, not the methods directly
let obj = await bus.getProxyObject('org.mpris.MediaPlayer2.playertest', '/org/mpris/MediaPlayer2');
let playerIface = obj.getInterface(PLAYER_IFACE);
let props = obj.getInterface('org.freedesktop.DBus.Properties');
let peer = obj.getInterface('org.freedesktop.DBus.Peer');
// position defaults to always being 0
let position = await props.Get(PLAYER_IFACE, 'Position');
expect(position).toEqual(new Variant('x', JSBI.BigInt(0)));
// when the getter is set, it should return what the getter returns
player.getPosition = function() {
return 99;
}
position = await props.Get(PLAYER_IFACE, 'Position');
expect(position).toEqual(new Variant('x', JSBI.BigInt(99)));
// Seek
let cb = jest.fn();
player.once('seek', cb);
await playerIface.Seek(99);
expect(cb).toHaveBeenCalledWith(99);
// SetPosition
cb = jest.fn();
player.once('position', cb);
await playerIface.SetPosition('/some/track', 100);
expect(cb).toHaveBeenCalledWith({ trackId: '/some/track', position: 100 });
cb = jest.fn();
playerIface.once('Seeked', cb);
player.seeked(200);
await peer.Ping();
expect(cb).toHaveBeenCalledWith(JSBI.BigInt(200));
});