mtg-playerinfo 1.3.0 → 1.3.2
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.
- package/.github/workflows/ci.yml +18 -0
- package/README.md +13 -6
- package/package.json +1 -1
- package/scripts/update-test-data.js +1 -1
- package/src/fetchers/untapped.js +44 -12
- package/test/data/topdeck.html +2 -2
- package/test/data/untapped.json +1 -104
- package/test/untapped.test.js +55 -12
- package/test/verboseLogging.test.js +12 -14
package/test/untapped.test.js
CHANGED
|
@@ -15,29 +15,75 @@ test('UntappedFetcher: parses most recent match and extracts MTGA rank', () => {
|
|
|
15
15
|
const matches = JSON.parse(fixtureJson)
|
|
16
16
|
|
|
17
17
|
const url = 'https://mtga.untapped.gg/profile/7de50700-c3f6-48e4-a38d-2add5b0d9b71/76DCDWCZS5FX5PIEEMUVY6GV74'
|
|
18
|
-
const result = fetcher.
|
|
18
|
+
const result = fetcher.parseMatches(matches, url)
|
|
19
19
|
|
|
20
20
|
assert.strictEqual(result.source, 'Untapped.gg')
|
|
21
21
|
assert.strictEqual(result.url, url)
|
|
22
22
|
|
|
23
|
-
assert.
|
|
23
|
+
assert.strictEqual(typeof result.mtga_rank, 'object')
|
|
24
|
+
|
|
25
|
+
// Format is either "Rank Tier" (e.g. "Diamond 2") or "Mythic #Place" (e.g. "Mythic #123")
|
|
26
|
+
if (result.mtga_rank.constructed !== undefined) {
|
|
27
|
+
assert.match(result.mtga_rank.constructed, /^(Bronze|Silver|Gold|Platinum|Diamond|Mythic)(\s\d+|\s#\d+)$/)
|
|
28
|
+
}
|
|
29
|
+
if (result.mtga_rank.limited !== undefined) {
|
|
30
|
+
assert.match(result.mtga_rank.limited, /^(Bronze|Silver|Gold|Platinum|Diamond|Mythic)(\s\d+|\s#\d+)$/)
|
|
31
|
+
}
|
|
24
32
|
})
|
|
25
33
|
|
|
26
34
|
test('UntappedFetcher: handles missing rank data', () => {
|
|
27
35
|
const fetcher = new UntappedFetcher()
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
36
|
+
const testMatches = [
|
|
37
|
+
{
|
|
38
|
+
super_format: 2,
|
|
39
|
+
friendly_ranking_class_after: null,
|
|
40
|
+
friendly_ranking_tier_after: null,
|
|
41
|
+
match_start: 1000
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
super_format: 1,
|
|
45
|
+
friendly_ranking_class_after: null,
|
|
46
|
+
friendly_ranking_tier_after: null,
|
|
47
|
+
match_start: 2000
|
|
48
|
+
}
|
|
49
|
+
]
|
|
32
50
|
|
|
33
51
|
const url = 'https://mtga.untapped.gg/profile/test-user/test-code'
|
|
34
|
-
const result = fetcher.
|
|
52
|
+
const result = fetcher.parseMatches(testMatches, url)
|
|
35
53
|
|
|
36
|
-
assert.strictEqual(result.mtga_rank,
|
|
54
|
+
assert.strictEqual('constructed' in result.mtga_rank, false)
|
|
55
|
+
assert.strictEqual('limited' in result.mtga_rank, false)
|
|
37
56
|
})
|
|
38
57
|
|
|
39
|
-
test('UntappedFetcher:
|
|
58
|
+
test('UntappedFetcher: formats Mythic rank with leaderboard place or percentile', () => {
|
|
40
59
|
const fetcher = new UntappedFetcher()
|
|
60
|
+
const testMatches = [
|
|
61
|
+
{
|
|
62
|
+
super_format: 2,
|
|
63
|
+
friendly_ranking_class_after: 'Mythic',
|
|
64
|
+
friendly_ranking_tier_after: null,
|
|
65
|
+
friendly_mythic_leaderboard_place_after: 123,
|
|
66
|
+
friendly_mythic_percentile_after: 101.5,
|
|
67
|
+
match_start: 1000
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
super_format: 1,
|
|
71
|
+
friendly_ranking_class_after: 'Mythic',
|
|
72
|
+
friendly_ranking_tier_after: null,
|
|
73
|
+
friendly_mythic_leaderboard_place_after: null,
|
|
74
|
+
friendly_mythic_percentile_after: 98.789,
|
|
75
|
+
match_start: 2000
|
|
76
|
+
}
|
|
77
|
+
]
|
|
78
|
+
|
|
79
|
+
const url = 'https://mtga.untapped.gg/profile/test-user/test-code'
|
|
80
|
+
const result = fetcher.parseMatches(testMatches, url)
|
|
81
|
+
|
|
82
|
+
assert.strictEqual(result.mtga_rank.constructed, 'Mythic #123')
|
|
83
|
+
assert.strictEqual(result.mtga_rank.limited, 'Mythic 98%')
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
test('UntappedFetcher: constructs correct API URL from two-part ID', () => {
|
|
41
87
|
const userId = '7de50700-c3f6-48e4-a38d-2add5b0d9b71'
|
|
42
88
|
const playerCode = '76DCDWCZS5FX5PIEEMUVY6GV74'
|
|
43
89
|
const id = `${userId}/${playerCode}`
|
|
@@ -53,6 +99,3 @@ test('UntappedFetcher: constructs correct API URL from two-part ID', () => {
|
|
|
53
99
|
const profileUrl = `https://mtga.untapped.gg/profile/${parts[0]}/${parts[1]}`
|
|
54
100
|
assert.strictEqual(profileUrl, 'https://mtga.untapped.gg/profile/7de50700-c3f6-48e4-a38d-2add5b0d9b71/76DCDWCZS5FX5PIEEMUVY6GV74')
|
|
55
101
|
})
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
@@ -13,7 +13,7 @@ test('PlayerInfoManager: verbose mode logs promoted properties', async () => {
|
|
|
13
13
|
}
|
|
14
14
|
]
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
const capturedLogs = []
|
|
17
17
|
const originalLog = console.log
|
|
18
18
|
console.log = (msg) => { capturedLogs.push(msg) }
|
|
19
19
|
|
|
@@ -45,12 +45,12 @@ test('PlayerInfoManager: verbose mode logs matching property values', async () =
|
|
|
45
45
|
}
|
|
46
46
|
]
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
const capturedLogs = []
|
|
49
49
|
const originalLog = console.log
|
|
50
50
|
console.log = (msg) => { capturedLogs.push(msg) }
|
|
51
51
|
|
|
52
52
|
try {
|
|
53
|
-
|
|
53
|
+
manager.mergeData(results, true)
|
|
54
54
|
assert.ok(capturedLogs.some(log => log.includes('🆗') && log.includes('name') && log.includes('Source2')),
|
|
55
55
|
'Should log matching property with 🆗 emoji')
|
|
56
56
|
assert.ok(capturedLogs.some(log => log.includes('🆗') && log.includes('team') && log.includes('Source2')),
|
|
@@ -76,7 +76,7 @@ test('PlayerInfoManager: verbose mode logs conflicting property values', async (
|
|
|
76
76
|
}
|
|
77
77
|
]
|
|
78
78
|
|
|
79
|
-
|
|
79
|
+
const capturedLogs = []
|
|
80
80
|
const originalLog = console.log
|
|
81
81
|
console.log = (msg) => { capturedLogs.push(msg) }
|
|
82
82
|
|
|
@@ -108,12 +108,12 @@ test('PlayerInfoManager: verbose mode uses photo emoji for photo conflicts', asy
|
|
|
108
108
|
}
|
|
109
109
|
]
|
|
110
110
|
|
|
111
|
-
|
|
111
|
+
const capturedLogs = []
|
|
112
112
|
const originalLog = console.log
|
|
113
113
|
console.log = (msg) => { capturedLogs.push(msg) }
|
|
114
114
|
|
|
115
115
|
try {
|
|
116
|
-
|
|
116
|
+
manager.mergeData(results, true)
|
|
117
117
|
assert.ok(capturedLogs.some(log => log.includes('🆕') && log.includes('photo')),
|
|
118
118
|
'Should log photo conflict with 🆕 emoji instead of 🆚')
|
|
119
119
|
} finally {
|
|
@@ -141,12 +141,12 @@ test('PlayerInfoManager: verbose mode logs with null/undefined properties', asyn
|
|
|
141
141
|
}
|
|
142
142
|
]
|
|
143
143
|
|
|
144
|
-
|
|
144
|
+
const capturedLogs = []
|
|
145
145
|
const originalLog = console.log
|
|
146
146
|
console.log = (msg) => { capturedLogs.push(msg) }
|
|
147
147
|
|
|
148
148
|
try {
|
|
149
|
-
|
|
149
|
+
manager.mergeData(results, true)
|
|
150
150
|
assert.ok(capturedLogs.some(log => log.includes('⬆️') && log.includes('bio') && log.includes('Source2')),
|
|
151
151
|
'Should promote bio from Source2 after Source1 had null')
|
|
152
152
|
assert.ok(capturedLogs.some(log => log.includes('⬆️') && log.includes('team') && log.includes('Source2')),
|
|
@@ -167,12 +167,12 @@ test('PlayerInfoManager: verbose mode is false by default and logs nothing', asy
|
|
|
167
167
|
}
|
|
168
168
|
]
|
|
169
169
|
|
|
170
|
-
|
|
170
|
+
const capturedLogs = []
|
|
171
171
|
const originalLog = console.log
|
|
172
172
|
console.log = (msg) => { capturedLogs.push(msg) }
|
|
173
173
|
|
|
174
174
|
try {
|
|
175
|
-
|
|
175
|
+
manager.mergeData(results, false)
|
|
176
176
|
assert.equal(capturedLogs.length, 0, 'Should not log when verbose is false')
|
|
177
177
|
} finally {
|
|
178
178
|
console.log = originalLog
|
|
@@ -194,13 +194,12 @@ test('PlayerInfoManager: verbose mode logs each property separately', async () =
|
|
|
194
194
|
}
|
|
195
195
|
]
|
|
196
196
|
|
|
197
|
-
|
|
197
|
+
const capturedLogs = []
|
|
198
198
|
const originalLog = console.log
|
|
199
199
|
console.log = (msg) => { capturedLogs.push(msg) }
|
|
200
200
|
|
|
201
201
|
try {
|
|
202
|
-
|
|
203
|
-
// Should have multiple promoted property logs
|
|
202
|
+
manager.mergeData(results, true)
|
|
204
203
|
const promotedLogs = capturedLogs.filter(log => log.includes('⬆️'))
|
|
205
204
|
assert.ok(promotedLogs.length >= 5, `Should log 5+ promoted properties, got ${promotedLogs.length}`)
|
|
206
205
|
assert.ok(promotedLogs.some(log => log.includes('name')))
|
|
@@ -212,4 +211,3 @@ test('PlayerInfoManager: verbose mode logs each property separately', async () =
|
|
|
212
211
|
console.log = originalLog
|
|
213
212
|
}
|
|
214
213
|
})
|
|
215
|
-
|