Skip to content

Bump eslint-plugin-sonarjs from 1.0.4 to 2.0.2 in the major group across 1 directory #6258

Bump eslint-plugin-sonarjs from 1.0.4 to 2.0.2 in the major group across 1 directory

Bump eslint-plugin-sonarjs from 1.0.4 to 2.0.2 in the major group across 1 directory #6258

GitHub Actions / JEST Tests succeeded Sep 3, 2024 in 0s

493 passed, 0 failed and 0 skipped

Tests passed successfully

✅ junit.xml

493 tests were completed in 21s with 493 passed, 0 failed and 0 skipped.

Test suite Passed Failed Skipped Time
src/app/accounts/destiny-account.test.ts 3✅ 572ms
src/app/armory/wishlist-collapser.test.ts 1✅ 82ms
src/app/bungie-api/http-client.test.ts 7✅ 81ms
src/app/destiny2/d2-definitions.test.ts 1✅ 2s
src/app/dim-api/reducer.test.ts 15✅ 5s
src/app/dim-ui/table-columns.test.ts 1✅ 134ms
src/app/hotkeys/hotkeys.test.ts 2✅ 66ms
src/app/inventory/d2-stores.test.ts 9✅ 7s
src/app/inventory/notes-hashtags.test.ts 26✅ 58ms
src/app/item-popup/item-popup-actions.test.ts 1✅ 4s
src/app/item-triage/triage-utils.test.ts 2✅ 357ms
src/app/loadout-analyzer/analysis.test.ts 7✅ 4s
src/app/loadout-builder/auto-stat-mod-utils.test.ts 7✅ 3s
src/app/loadout-builder/item-filter.test.ts 11✅ 3s
src/app/loadout-builder/process-utils.test.ts 38✅ 5s
src/app/loadout-builder/process-worker/stats-set.test.ts 1✅ 67ms
src/app/loadout-builder/process/mappers.test.ts 3✅ 3s
src/app/loadout-builder/utils.test.ts 1✅ 68ms
src/app/loadout-drawer/loadout-drawer-reducer.test.ts 36✅ 6s
src/app/loadout/loadout-share/loadout-import.test.ts 10✅ 336ms
src/app/loadout/mod-assignment-utils.test.ts 5✅ 3s
src/app/register-service-worker.test.ts 3✅ 162ms
src/app/search/autocomplete.test.ts 38✅ 622ms
src/app/search/loadouts/loadout-search-filter.test.ts 2✅ 374ms
src/app/search/query-parser.test.ts 75✅ 208ms
src/app/search/search-config.test.ts 57✅ 308ms
src/app/search/search-filter.test.ts 34✅ 139ms
src/app/settings/vault-grouping.test.ts 3✅ 4s
src/app/store-stats/AccountCurrencies.test.tsx 2✅ 180ms
src/app/utils/collections.test.ts 10✅ 70ms
src/app/utils/intl.test.ts 33✅ 181ms
src/app/utils/memoize.test.ts 1✅ 77ms
src/app/utils/promises.test.ts 1✅ 51ms
src/app/utils/time.test.ts 36✅ 391ms
src/app/utils/undo-redo-history.test.ts 1✅ 591ms
src/app/vendors/d2-vendors.test.ts 1✅ 2s
src/app/wishlists/wishlist-file.test.ts 1✅ 77ms
src/browsercheck.test.ts 7✅ 137ms
src/testing/precache-manifest.test.ts 1✅ 2s

✅ src/app/accounts/destiny-account.test.ts

generatePlatforms
  ✅ gets one D2 account and one D1 account
  ✅ handles when D2 accounts are in profilesWithErrors and error code DestinyUnexpectedError
  ✅ does not return D2 account when they are in profilesWithErrors and error code DestinyAccountNotFound

✅ src/app/armory/wishlist-collapser.test.ts

perkConsolidator
  ✅ does its thing

✅ src/app/bungie-api/http-client.test.ts

✅ check Request builder for [Function getItem]
✅ check Request builder for [Function getProfile]
✅ check Request builder for [Function getLinkedProfiles]
✅ check Request builder for [Function getVendor]
✅ check Request builder for [Function pullFromPostmaster]
✅ should throw an error if there is no room in the destination
✅ should throw an error if API is down for maintenance

✅ src/app/destiny2/d2-definitions.test.ts

✅ something

✅ src/app/dim-api/reducer.test.ts

setSetting
  ✅ changes settings
setItemTag
  ✅ sets tags if there were none before
  ✅ clears set tags
setItemHashTag
  ✅ sets tags if there were none before
  ✅ clears set tags
prepareToFlushUpdates
  ✅ can coalesce settings
  ✅ can handle multiple profile updates
  ✅ can handle multiple profile updates with settings last
  ✅ can handle loadouts
  ✅ can handle tag stuff
finishedUpdates
  ✅ can mark success
saveSearch
  ✅ can save valid queries
  ✅ can unsave valid queries
  ✅ does not save invalid queries
  ✅ can unsave invalid queries

✅ src/app/dim-ui/table-columns.test.ts

useTableColumnSorts
  ✅ use cases

✅ src/app/hotkeys/hotkeys.test.ts

✅ stacks hotkeys
✅ allows Escape hotkey when an input is focused

✅ src/app/inventory/d2-stores.test.ts

process stores
  ✅ can process stores without errors
  ✅ all sockets' plugged is present in the list of plugOptions
  ✅ intrinsic sockets should have only one plugOption
  ✅ sparrows should have perks
  ✅ items with stats should have at least one nonzero stat
  ✅ item perks can be marked as cannotCurrentlyRoll
  ✅ generates a correct weapon CSV export
  ✅ generates a correct armor CSV export
  ✅ generates a correct ghost CSV export

✅ src/app/inventory/notes-hashtags.test.ts

✅ getHashtagsFromNote: #foo #bar
✅ getHashtagsFromNote: #foo, #bar
✅ getHashtagsFromNote: This note has #foo tag and also#bar
✅ getHashtagsFromNote: #foo#bar
✅ getHashtagsFromNote: #foo,#bar
✅ getHashtagsFromNote: #foo-#bar
✅ getHashtagsFromNote: Emoji #🤯 tags
✅ collectNotesHashtags should get a unique set of hashtags from multiple notes
✅ appendedToNote: undefined + A note => A note
✅ appendedToNote: A note + #fancy => A note #fancy
✅ appendedToNote: A #fancy note + #fancy => A #fancy note
✅ appendedToNote: #pve #s20 + #pve #stasis => #pve #s20 #stasis
✅ appendedToNote: #pve #s20 + #void #pve #stasis => #pve #s20 #void #stasis
✅ appendedToNote: My favorite! #pve #s20 + #pve #stasis => My favorite! #pve #s20 #stasis
✅ appendedToNote: My favorite!
#pve #s20 + #pve #stasis => My favorite!
#pve #s20 #stasis
✅ appendedToNote: My favorite!
#pve #s20 + #pve
#stasis => My favorite!
#pve #s20
#stasis
✅ appendedToNote: #pve, #s20 + #pve #stasis => #pve, #s20 #stasis
✅ appendedToNote: #void + #void #voidwalker #other => #void #voidwalker #other
✅ removedFromNote: A note - A note =>
✅ removedFromNote: A note #fancy - #fancy => A note
✅ removedFromNote: A #fancy note - #fancy => A note
✅ removedFromNote: #voidwalker #void - #void => #voidwalker
✅ removedFromNote: #voidwalker #void - void => #voidwalker #void
✅ removedFromNote: #voidwalker My #void gun - My #void gun => #voidwalker
✅ removedFromNote: #pve, #s20, #stasis - #s20 => #pve, , #stasis
✅ removedFromNote: Void void void arc - void => Void arc

✅ src/app/item-popup/item-popup-actions.test.ts

✅ handles an equipped item

✅ src/app/item-triage/triage-utils.test.ts

triage armor comparison works
  ✅ works for non-artifice armor
  ✅ works for artifice armor

✅ src/app/loadout-analyzer/analysis.test.ts

basic loadout analysis finding tests
  ✅ finds MissingItems
  ✅ finds InvalidMods
  ✅ finds EmptyFragmentSlots/TooManyFragments
  ✅ finds InvalidSearchQuery
  ✅ finds UsesSeasonalMods/ModsDontFit
  ✅ finds DoesNotRespectExotic
  ✅ finds DoesNotSatisfyStatConstraints

✅ src/app/loadout-builder/auto-stat-mod-utils.test.ts

process-utils auto mod structure
  ✅ snapshot of mod defs when assuming general for auto mods
  ✅ snapshot of mod defs when assuming cheapgeneral for auto mods
  ✅ different ways of hitting target stats with 5 remaining general mods (using artifice mods: false)
  ✅ different ways of hitting target stats with 3 remaining general mods (using artifice mods: false)
  ✅ different ways of hitting target stats with 1 remaining general mods (using artifice mods: true)
  ✅ different ways of hitting target stats with 0 remaining general mods (using artifice mods: true)
  ✅ different ways of hitting target stats with 5 remaining general mods (using artifice mods: true)

✅ src/app/loadout-builder/item-filter.test.ts

loadout-builder item-filter
  ✅ filters nothing out when no filters specified
  ✅ filters out items with insufficient energy capacity
  ✅ filters nothing out when any exotic
  ✅ removes exotics when no exotic
  ✅ filters nothing out when infeasible filter
  ✅ ignores filter for certain slots
  ✅ filter applies to some slots
  ✅ specific exotic filtered
  ✅ any exotic does not ignore filters if they can be satisfied
  ✅ any exotic ignores filters if they cannot be satisfied
  ✅ mod assignment may cause exotic slot to not have options

✅ src/app/loadout-builder/process-utils.test.ts

process-utils mod assignment
  ✅ generates the correct number of permutations for 1 unique mods
  ✅ generates the correct number of permutations for 2 unique mods
  ✅ generates the correct number of permutations for 3 unique mods
  ✅ generates the correct number of permutations for 4 unique mods
  ✅ generates the correct number of permutations for 5 unique mods
  ✅ can fit all mods when there are no mods
  ✅ can fit five general mods
  ✅ it can fit a general mod into a single item at index 0
  ✅ it can fit a general mod into a single item at index 1
  ✅ it can fit a general mod into a single item at index 2
  ✅ it can fit a general mod into a single item at index 3
  ✅ it can fit a general mod into a single item at index 4
  ✅ it can fit five activity mods
  ✅ it can't fit five activity mods
  ✅ it can fit a activity mod into a single item at index 0
  ✅ it can fit a activity mod into a single item at index 1
  ✅ it can fit a activity mod into a single item at index 2
  ✅ it can fit a activity mod into a single item at index 3
  ✅ it can fit a activity mod into a single item at index 4
  ✅ can fit general, activity, and combat mods if there is enough energy
  ✅ can't fit general, activity, and combat mods if there isn't enough energy
  ✅ can't fit mods if general mods have too much energy
  ✅ can't fit mods if combat mods have too much energy
  ✅ can't fit mods if activity mods have too much energy
process-utils auto mods
  ✅ the problem is solvable
  ✅ higher stats means we cannot find a viable set of picks
  ✅ we need all artifice mod slots
  ✅ we need all the energy capacity in all general mod slots
  ✅ activity mod cannot go into the other item if we want to hit stats
process-utils optimal mods
  ✅ set with stats [80, 70, 80, 40, 30, 30], energies [0, 3, 0, 3, 0], numArtifice 0 yields tiers [8, 7, 8, 6, 3, 3]
  ✅ set with stats [63, 70, 59, 35, 30, 30], energies [2, 0, 0, 0, 0], numArtifice 3 yields tiers [7, 7, 6, 3, 3, 3]
  ✅ set with stats [80, 65, 80, 35, 30, 30], energies [1, 0, 0, 0, 0], numArtifice 2 yields tiers [8, 7, 8, 4, 3, 3]
  ✅ set with stats [68, 66, 30, 30, 30, 30], energies [0, 0, 0, 0, 0], numArtifice 4 yields tiers [8, 6, 3, 3, 3, 3]
  ✅ set with stats [68, 66, 30, 30, 11, 30], energies [2, 2, 0, 0, 0], numArtifice 4 yields tiers [7, 6, 3, 3, 3, 3]
  ✅ set with stats [30, 61, 30, 30, 30, -14], energies [5, 5, 5, 5, 5], numArtifice 5 yields tiers [5, 6, 3, 3, 3, 3]
  ✅ set with stats [18, 80, 80, 26, 80, 30], energies [0, 0, 0, 3, 0], numArtifice 4 produces exact stats [30, 80, 80, 31, 80, 30]
  ✅ set with stats [26, 80, 80, 18, 80, 30], energies [0, 0, 0, 3, 0], numArtifice 4 produces exact stats [32, 80, 80, 31, 80, 30]
✅ process-utils activity mods

✅ src/app/loadout-builder/process-worker/stats-set.test.ts

✅ insertAll 1

✅ src/app/loadout-builder/process/mappers.test.ts

lo process mappers
  ✅ mapped energy capacity is 10 when assumed masterwork is used
  ✅ mapped energy capacity is the items when assumed masterwork is not used
  ✅ mapped energy capacity defaults to MIN_LO_ITEM_ENERGY when assumed masterwork is not used and the item energy is low

✅ src/app/loadout-builder/utils.test.ts

statTierWithHalf
  ✅ checks proper visual tier formatting

✅ src/app/loadout-drawer/loadout-drawer-reducer.test.ts

addItem
  ✅ can add an item to an empty loadout
  ✅ saves the crafted date for crafted items
  ✅ can add an item to a loadout that is already there as a noop
  ✅ can add an unequipped item to a loadout
  ✅ defaults equip when unset
  ✅ can replace the currently equipped item
  ✅ can switch an equipped item to unequipped if added again with the equip flag set
  ✅ can switch an unequipped item to equipped if added again with the equip flag set
  ✅ handles duplicates even if the new version is a reshaped version of the one saved in the loadout
  ✅ fills in socket overrides when adding a subclass
  ✅ replaces the existing subclass when adding a new one
  ✅ does nothing if the item cannot be in a loadout
  ✅ does nothing if the item is for the wrong class
  ✅ does nothing when adding class-specific item to any-class loadout
  ✅ removes class-specific items when saving as "any class"
  ✅ does nothing if the bucket is already at capacity
  ✅ de-equips an exotic in another bucket when equipping a new exotic
removeItem
  ✅ promotes an unequipped item to equipped when the equipped item is removed
  ✅ does nothing when asked to remove an item that is not in the loadout
toggleEquipped
  ✅ can toggle an equipped item to unequipped
  ✅ can toggle an unequipped item to equipped
  ✅ does nothing when applied to a subclass
  ✅ does not lose socket overrides
removeMod
  ✅ removes a mod by inventory item hash
clearSubclass
  ✅ removes the subclass
setLoadoutSubclassFromEquipped
  ✅ correctly populates the subclass and its overrides
fillLoadoutFromEquipped
  ✅ can fill in weapons
  ✅ can fill in armor
  ✅ can fill in everything
  ✅ will not overwrite mods if they are already there
  ✅ will not overwrite artifact unlocks if they are already there
fillLoadoutFromUnequipped
  ✅ fills in unequipped items but does not change an existing item
  ✅ fills in unequipped items for a single category
  ✅ fills in unequipped items for a single category without overflow
clearBucketCategory
  ✅ clears the weapons category
  ✅ clears the general category without clearing subclass

✅ src/app/loadout/loadout-share/loadout-import.test.ts

dim.gg loadout share links parsing
  ✅ valid dim.gg loadout link 4j5nz4q
  ✅ valid dim.gg loadout link 4j5nz4q/Heart-of-Inmost-Light-Arc
  ✅ valid dim.gg loadout link dim.gg/4j5nz4q
  ✅ valid dim.gg loadout link https://dim.gg/4j5nz4q
  ✅ valid dim.gg loadout link https://dim.gg/4j5nz4q/
  ✅ valid dim.gg loadout link http://dim.gg/4j5nz4q/
  ✅ valid dim.gg loadout link https://dim.gg/4j5nz4q/Heart-of-Inmost-Light-Arc
  ✅ valid direct loadout link https://beta.destinyitemmanager.com/loadouts?loadout=%7B%22id%22%3A%22jf7w53i%22%2C%22name%22%3A%22Simple+Loadout%22%2C%22classType%22%3A3%2C%22clearSpace%22%3Afalse%2C%22equipped%22%3A%5B%5D%2C%22unequipped%22%3A%5B%5D%2C%22createdAt%22%3A1668353218495%2C%22parameters%22%3A%7B%22mods%22%3A%5B2623485440%5D%2C%22lockArmorEnergyType%22%3A1%2C%22assumeArmorMasterwork%22%3A1%7D%7D
  ✅ valid direct loadout link https://app.destinyitemmanager.com/loadouts?loadout={%22name%22:%22robojumper%27s%20loadout%22,%22classType%22:0,%22equipped%22:[{%22id%22:%226917529830717539496%22,%22hash%22:2531963421},{%22id%22:%226917529836701241352%22,%22hash%22:1937552980},{%22id%22:%226917529682880957257%22,%22hash%22:1399243961},{%22id%22:%226917529643654891819%22,%22hash%22:1322544481},{%22id%22:%226917529208297337712%22,%22hash%22:613647804,%22socketOverrides%22:{%220%22:3260056808,%221%22:469281040,%222%22:1399217,%223%22:3866705246,%224%22:2031919264,%225%22:3469412971,%226%22:537774540,%227%22:3469412975,%228%22:2483898429,%229%22:2483898430}}],%22parameters%22:{%22mods%22:[667313240,3521781036,1499759470,2051366208,1740246051,1740246051,1740246051,2187989982,2187989982,1977242754,1977242752,445559589,445559589]}}
  ✅ valid direct loadout link https://beta.destinyitemmanager.com/4611686018483139177/d2/loadouts?loadout=%7B%22id%22%3A%22d2ap%22%2C%22name%22%3A%22D2ArmorPicker%20Loadout%22%2C%22classType%22%3A1%2C%22parameters%22%3A%7B%22statConstraints%22%3A%5B%7B%22statHash%22%3A2996146975%2C%22minTier%22%3A5%2C%22maxTier%22%3A10%7D%2C%7B%22statHash%22%3A392767087%2C%22minTier%22%3A10%2C%22maxTier%22%3A10%7D%2C%7B%22statHash%22%3A1943323491%2C%22minTier%22%3A0%2C%22maxTier%22%3A10%7D%2C%7B%22statHash%22%3A1735777505%2C%22minTier%22%3A0%2C%22maxTier%22%3A10%7D%2C%7B%22statHash%22%3A144602215%2C%22minTier%22%3A0%2C%22maxTier%22%3A10%7D%2C%7B%22statHash%22%3A4244567218%2C%22minTier%22%3A10%2C%22maxTier%22%3A10%7D%5D%2C%22mods%22%3A%5B1484685887%2C2979815167%2C2850583378%2C2850583378%5D%2C%22assumeArmorMasterwork%22%3A3%2C%22lockArmorEnergyType%22%3A1%2C%22exoticArmorHash%22%3A2773056939%7D%2C%22equipped%22%3A%5B%7B%22id%22%3A%226917529342535580813%22%2C%22hash%22%3A2773056939%7D%2C%7B%22id%22%3A%226917529801497037343%22%2C%22hash%22%3A1148597205%7D%2C%7B%22id%22%3A%226917529793250524983%22%2C%22hash%22%3A145651147%7D%2C%7B%22id%22%3A%226917529807139650343%22%2C%22hash%22%3A2724719415%7D%2C%7B%22id%22%3A%2212345%22%2C%22hash%22%3A2453351420%2C%22socketOverrides%22%3A%7B%227%22%3A2661180602%2C%228%22%3A2272984671%7D%7D%5D%2C%22unequipped%22%3A%5B%5D%2C%22clearSpace%22%3Afalse%7D

✅ src/app/loadout/mod-assignment-utils.test.ts

mod-assignment-utils plugging strategy
  ✅ reset assignments are present and required
  ✅ keeps existing mod in place if removal optional
  ✅ removes existing mod if needed
  ✅ prefers replacing mutual exclusion mod
  ✅ succeeds even if we choose not to replace in same slot

✅ src/app/register-service-worker.test.ts

isNewVersion
  ✅ should recognize two identical versions
  ✅ should newer versions
  ✅ should ignore older versions

✅ src/app/search/autocomplete.test.ts

autocompleteTermSuggestions
  ✅ autocomplete within query for plain string match {jotu} - {jötunn}
  ✅ autocomplete within query for {is:haspower is:b}
  ✅ autocomplete within query for {(is:blue ju|n)}
  ✅ autocomplete within query for {is:bow is:v|oid}
  ✅ autocomplete within query for {season:>outl}
  ✅ autocomplete within query for {not(}
  ✅ autocomplete within multi-word query for {arctic haz} should suggest {name:"arctic haze"}
  ✅ autocomplete within multi-word query for {is:weapon arctic haz| -is:exotic} should suggest {is:weapon name:"arctic haze" -is:exotic}
  ✅ autocomplete within multi-word query for {name:"arctic haz} should suggest {name:"arctic haze"}
  ✅ autocomplete within multi-word query for {name:'arctic haz} should suggest {name:"arctic haze"}
  ✅ autocomplete within multi-word query for {name:"foo" arctic haz} should suggest {name:"foo" name:"arctic haze"}
  ✅ autocomplete within multi-word query for {ager's sce} should suggest {name:"ager's scepter"}
  ✅ autocomplete within multi-word query for {the last word} should suggest {name:"the last word"}
  ✅ autocomplete within multi-word query for {acd/0 fee} should suggest {name:"acd/0 feedback fence"}
  ✅ autocomplete within multi-word query for {stat:rpm:200 first in, last} should suggest {stat:rpm:200 name:"first in, last out"}
  ✅ autocomplete within multi-word query for {two-tail} should suggest {name:"two-tailed fox"}
  ✅ autocomplete within multi-word query for {(is:a or is:b) and (is:c or multi w|)} should suggest {(is:a or is:b) and (is:c or name:"multi word")}
  ✅ autocomplete within multi-word query for {"rare curio" arctic haz} should suggest {"rare curio" name:"arctic haze"}
  ✅ autocomplete within multi-word query for {"rare curio" or arctic haz} should suggest {"rare curio" or name:"arctic haze"}
  ✅ autocomplete within multi-word query for {toil and trou} should suggest {name:"toil and trouble"}
  ✅ autocomplete within multi-word query for {perkname:"fate of} should suggest {perkname:"fate of all fools"}
  ✅ autocomplete within multi-word query for {perkname:fate of} should suggest {perkname:"fate of all fools"}
  ✅ autocomplete within multi-word query for {rare curio or arctic haz} should suggest {rare curio or name:"arctic haze"}
  ✅ autocomplete within multi-word query for {name:heritage arctic haze} should suggest {name:heritage name:"arctic haze"}
  ✅ autocomplete within multi-word query for {adept pali} should suggest {adept name:"the palindrome"}
filterSortRecentSearches
  ✅ filter/sort recent searches for query ||
  ✅ filter/sort recent searches for query |high|
  ✅ check saved search highlighting for query ||
  ✅ check saved search highlighting for query |craft|
  ✅ check saved search highlighting for query |craftable|
  ✅ check saved search highlighting for query |crafted|
filterComplete
  ✅ autocomplete terms for |is:b|
  ✅ autocomplete terms for |jun|
  ✅ autocomplete terms for |sni|
  ✅ autocomplete terms for |stat:mob|
  ✅ autocomplete terms for |stat|
  ✅ autocomplete terms for |stat:|
  ✅ autocomplete terms for |ote|

✅ src/app/search/loadouts/loadout-search-filter.test.ts

buildSearchConfig
  ✅ generates a reasonable filter map
  ✅ filter formats specify unambiguous formats

✅ src/app/search/query-parser.test.ts

✅ parse |is:blue is:haspower -is:maxpower|
✅ parse |is:blue is:haspower not:maxpower|
✅ parse |not:maxpower|
✅ parse |not -not:maxpower|
✅ parse |not not not:maxpower|
✅ parse |is:blue is:weapon or is:armor not:maxpower|
✅ parse |not not:maxpower|
✅ parse |-is:equipped is:haspower is:incurrentchar|
✅ parse |-source:garden -source:lastwish sunsetsafter:arrival|
✅ parse |-is:exotic -is:locked -is:maxpower -is:tagged stat:total:<55|
✅ parse |(is:weapon is:sniperrifle) or (is:armor modslot:arrival)|
✅ parse |(is:weapon and is:sniperrifle) or not (is:armor and modslot:arrival)|
✅ parse |is:weapon and is:sniperrifle or not is:armor and modslot:arrival|
✅ parse |is:weapon is:sniperrifle or not is:armor modslot:arrival|
✅ parse |is:weapon is:sniperrifle or is:armor and modslot:arrival|
✅ parse |is:weapon (is:sniperrifle or (is:armor and modslot:arrival))|
✅ parse |-(power:>1000 and -modslot:arrival)|
✅ parse |( power:>1000 and -modslot:arrival ) |
✅ parse |- is:exotic - (power:>1000)|
✅ parse |is:armor2.0|
✅ parse |not forgotten|
✅ parse |cluster tracking|
✅ parse |name:"Hard Light"|
✅ parse |name:'Hard Light'|
✅ parse |name:"Gahlran's Right Hand"|
✅ parse |-witherhoard|
✅ parse |perk:수집가|
✅ parse |perk:"수집가"|
✅ parse |"수집가"|
✅ parse |수집가|
✅ parse |is:rocketlauncher -"cluster" -"tracking module"|
✅ parse |is:rocketlauncher -"cluster" -'tracking module'|
✅ parse |is:rocketlauncher (perk:"cluster" or perk:"tracking module")|
✅ parse |(is:hunter power:>=540) or (is:warlock power:>=560)|
✅ parse |"grenade launcher reserves"|
✅ parse |“grenade launcher reserves”|
✅ parse |‘grenade launcher reserves’|
✅ parse |(("test" or "test") and "test")|
✅ parse |  (
    (
    (is:weapon -is:maxpower powerlimit:1060 or tag:junk or is:blue)
    or
    (
    (is:armor -is:exotic -is:classitem)
  
    -(is:titan (basestat:recovery:>=18 or basestat:total:>=63))
    -(is:hunter ((basestat:recovery:>=13 basestat:mobility:>=18) or basestat:recovery:>15 or basestat:total:>=63))
    -(is:warlock ((basestat:recovery:>=18 discipline:>=17) or basestat:total:>=63))
  
    -(
    ((basestat:mobility:>=18 basestat:resilience:>=13) or
    (basestat:mobility:>=18 basestat:recovery:>=13) or
    (basestat:mobility:>=18 basestat:discipline:>=13) or
    (basestat:mobility:>=18 basestat:intellect:>=13) or
    (basestat:mobility:>=18 basestat:strength:>=13) or
    (basestat:resilience:>=18 basestat:mobility:>=13) or
    (basestat:resilience:>=18 basestat:recovery:>=13) or
    (basestat:resilience:>=18 basestat:discipline:>=13) or
    (basestat:resilience:>=18 basestat:intellect:>=13) or
    (basestat:resilience:>=18 basestat:strength:>=13) or
    (basestat:recovery:>=18 basestat:mobility:>=13) or
    (basestat:recovery:>=18 basestat:resilience:>=13) or
    (basestat:recovery:>=18 basestat:discipline:>=13) or
    (basestat:recovery:>=18 basestat:intellect:>=13) or
    (basestat:recovery:>=18 basestat:strength:>=13) or
    (basestat:discipline:>=18 basestat:mobility:>=13) or
    (basestat:discipline:>=18 basestat:resilience:>=13) or
    (basestat:discipline:>=18 basestat:recovery:>=13) or
    (basestat:discipline:>=18 basestat:intellect:>=13) or
    (basestat:discipline:>=18 basestat:strength:>=13) or
    (basestat:intellect:>=18 basestat:mobility:>=13) or
    (basestat:intellect:>=18 basestat:resilience:>=13) or
    (basestat:intellect:>=18 basestat:recovery:>=13) or
    (basestat:intellect:>=18 basestat:discipline:>=13) or
    (basestat:intellect:>=18 basestat:strength:>=13) or
    (basestat:strength:>=18 basestat:mobility:>=13) or
    (basestat:strength:>=18 basestat:resilience:>=13) or
    (basestat:strength:>=18 basestat:recovery:>=13) or
    (basestat:strength:>=18 basestat:discipline:>=13) or
    (basestat:strength:>=18 basestat:intellect:>=13))
    )
  
    -(
    ((basestat:mobility:>=13 basestat:resilience:>=13 basestat:recovery:>=13) or
    (basestat:mobility:>=13 basestat:resilience:>=13 basestat:discipline:>=13) or
    (basestat:mobility:>=13 basestat:resilience:>=13 basestat:intellect:>=13) or
    (basestat:mobility:>=13 basestat:resilience:>=13 basestat:strength:>=13) or
    (basestat:mobility:>=13 basestat:recovery:>=13 basestat:discipline:>=13) or
    (basestat:mobility:>=13 basestat:recovery:>=13 basestat:intellect:>=13) or
    (basestat:mobility:>=13 basestat:recovery:>=13 basestat:strength:>=13) or
    (basestat:mobility:>=13 basestat:discipline:>=13 basestat:intellect:>=13) or
    (basestat:mobility:>=13 basestat:discipline:>=13 basestat:strength:>=13) or
    (basestat:mobility:>=13 basestat:intellect:>=13 basestat:strength:>=13) or
    (basestat:resilience:>=13 basestat:recovery:>=13 basestat:discipline:>=13) or
    (basestat:resilience:>=13 basestat:recovery:>=13 basestat:intellect:>=13) or
    (basestat:resilience:>=13 basestat:recovery:>=13 basestat:strength:>=13) or
    (basestat:resilience:>=13 basestat:discipline:>=13 basestat:intellect:>=13) or
    (basestat:resilience:>=13 basestat:discipline:>=13 basestat:strength:>=13) or
    (basestat:resilience:>=13 basestat:intellect:>=13 basestat:strength:>=13) or
    (basestat:recovery:>=13 basestat:discipline:>=13 basestat:intellect:>=13) or
    (basestat:recovery:>=13 basestat:discipline:>=13 basestat:strength:>=13) or
    (basestat:recovery:>=13 basestat:intellect:>=13 basestat:strength:>=13) or
    (basestat:discipline:>=13 basestat:intellect:>=13 basestat:strength:>=13))
    )
  
    -(basestat:mobility:>=8 basestat:resilience:>=8 basestat:recovery:>=8 basestat:discipline:>=8 basestat:intellect:>=8 basestat:strength:>=8)
    )
  
    or
    (is:classitem ((is:dupelower -is:modded) or (is:sunset))) 
    or
    (is:armor -powerlimit:>1060) 
    or
    (is:armor is:blue)
    )
    -tag:keep -tag:archive -tag:favorite -tag:infuse -is:maxpower -power:>=1260 -is:inloadout -is:masterwork
    )|
✅ parse |not forgotten|
✅ parse |not (forgotten)|
✅ parse |not "forgotten"|
✅ parse |gnawing hunger|
✅ parse |/* My cool search */ is:armor|
✅ parse |  /* My cool search */
 is:armor|
✅ parse |/* My cool search */ (/* armor */ is:armor and is:blue) or (/*weapons*/ is:weapon and perkname:"Kill Clip")|
✅ |is:blue is:weapon or is:armor not:maxpower| is equivalent to |is:blue and (is:weapon or is:armor) and -is:maxpower|
✅ |not forgotten| is equivalent to |-"forgotten"|
✅ |cluster tracking| is equivalent to |"cluster" and "tracking"|
✅ |is:weapon and is:sniperrifle or not is:armor and modslot:arrival| is equivalent to |(is:weapon and is:sniperrifle) or (-is:armor and modslot:arrival)|
✅ |is:weapon is:sniperrifle or not is:armor modslot:arrival| is equivalent to |is:weapon and (is:sniperrifle or -is:armor) and modslot:arrival|
✅ |is:weapon is:sniperrifle or is:armor and modslot:arrival| is equivalent to |is:weapon and (is:sniperrifle or (is:armor and modslot:arrival))|
✅ |is:rocketlauncher perk:"cluster" or perk:"tracking module"| is equivalent to |is:rocketlauncher (perk:"cluster" or perk:"tracking module")|
✅ |is:blue (is:rocketlauncher| is equivalent to |is:blue is:rocketlauncher|
✅ |  is:blue  | is equivalent to |is:blue|
✅ |is:blue is:haspower not:maxpower| is canonically |is:blue is:haspower -is:maxpower|
✅ |is:weapon and is:sniperrifle or not is:armor and modslot:arrival| is canonically |(is:weapon is:sniperrifle) or (-is:armor modslot:arrival)|
✅ |is:rocketlauncher perk:"cluster" or perk:'tracking module'| is canonically |is:rocketlauncher (perk:cluster or perk:"tracking module")|
✅ |( power:>1000 and -modslot:arrival ) | is canonically |power:>1000 -modslot:arrival|
✅ |food fight| is canonically |food and fight|
✅ |/* My cool search   */
 is:armor| is canonically |/* my cool search */ is:armor|
✅ |/* My cool search */ (/* armor */ is:armor and is:blue) or (/*weapons*/ is:weapon and perkname:"Kill Clip")| is canonically |/* my cool search */ (is:armor is:blue) or (is:weapon perkname:"kill clip")|
✅ |inloadout:"----<()>fast"| is canonically |inloadout:"----<()>fast"|
✅ |perkname:"foobar"| is canonically |perkname:foobar|
✅ |perkname:'foo bar'| is canonically |perkname:"foo bar"|
✅ |perkname:"foobar"| is canonically |perkname:foobar|
✅ |perkname:'foo"bar'| is canonically |perkname:'foo"bar'|
✅ |perkname:"foo\"bar"| is canonically |perkname:'foo"bar'|
✅ |perkname:'foo\"ba\'r'| is canonically |perkname:'foo"ba\'r'|
✅ |foobar| quoting roundtrip
✅ |Foo\bar| quoting roundtrip
✅ |My cool loadout| quoting roundtrip
✅ |My "cool" loadout| quoting roundtrip
✅ |My "cool" loadout's little brother| quoting roundtrip
✅ |My "cool" load\out's little brother| quoting roundtrip

✅ src/app/search/search-config.test.ts

buildSearchConfig
  ✅ generates a reasonable filter map
  ✅ filter formats specify unambiguous formats
validateQuery
  ✅ is: filter is:crafted - validity true
  ✅ is: filter not:crafted - validity true
  ✅ is: filter crafted:is - validity false
  ✅ query filter tag:favorite - validity true
  ✅ query filter tag:none - validity true
  ✅ query filter tag:any - validity false
  ✅ query filter is:tag - validity false
  ✅ query filter tag:<5 - validity false
  ✅ query filter tag:recovery:17 - validity false
  ✅ freeform filter notes:#hashtag - validity true
  ✅ freeform filter notes:verbatim:colon - validity true
  ✅ freeform filter notes"with spaces" - validity true
  ✅ freeform filter notes:<5 - validity true
  ✅ freeform filter is:notes - validity false
  ✅ mixed filter is:masterwork - validity true
  ✅ mixed filter masterwork:range - validity true
  ✅ mixed filter masterwork:<5 - validity true
  ✅ mixed filter masterwork:=5 - validity true
  ✅ mixed filter masterwork:5 - validity true
  ✅ mixed filter masterwork:rnage - validity false
  ✅ mixed filter masterwork:<range - validity false
  ✅ mixed filter masterwork:range:5 - validity false
  ✅ stat filter stat:recovery:5 - validity true
  ✅ stat filter stat:recovery:<=5 - validity true
  ✅ stat filter stat:recovery+discipline:>=5 - validity true
  ✅ stat filter stat:highest&secondhighest:>20 - validity true
  ✅ stat filter stat:highest&recovery+strength&strength&range:>20 - validity true
  ✅ stat filter basestat:range:>50 - validity true
  ✅ stat filter stat:badstat:>20 - validity false
  ✅ stat filter stat:badstat&badcombo:>20 - validity false
  ✅ stat filter stat:too&+many:>20 - validity false
  ✅ stat filter is:stat - validity false
  ✅ stat filter stat:recovery - validity false
  ✅ stat filter stat:=5 - validity false
  ✅ search string count:2 - validity true
  ✅ search string count:=2 - validity true
  ✅ search string count:<=2 - validity true
  ✅ search string count:<=2.5 - validity true
  ✅ search string is:count - validity false
  ✅ search string count:count - validity false
  ✅ search string count:recovery - validity false
  ✅ search string count:<=2:=2 - validity false
  ✅ search string count:<2> - validity false
  ✅ search string season:worthy - validity true
  ✅ search string season:<=worthy - validity true
  ✅ search string season:=worthy - validity true
  ✅ search string season:>=arrival - validity true
  ✅ search string season:222 - validity true
  ✅ search string season:=10 - validity true
  ✅ search string season:>2.5 - validity true
  ✅ search string is:season - validity false
  ✅ search string season:1redwar - validity false
  ✅ search string season:season - validity false
  ✅ search string season:arrivals - validity false
  ✅ search string season:arrivalworthy - validity false

✅ src/app/search/search-filter.test.ts

generateSuggestionsForFilter
  ✅ full suggestions for filter format 'undefined', keyword '[ 'a', 'b', 'c' ]' with suggestions undefined, overload undefined
  ✅ full suggestions for filter format 'query', keyword 'a' with suggestions [ 'b', 'c' ], overload undefined
  ✅ full suggestions for filter format 'stat', keyword 'a' with suggestions [ 'b', 'c' ], overload undefined
  ✅ full suggestions for filter format 'range', keyword 'a' with suggestions undefined, overload undefined
  ✅ full suggestions for filter format 'range', keyword 'a' with suggestions undefined, overload { worthy: 10, arrivals: 11 }
  ✅ full suggestions for filter format 'freeform', keyword 'a' with suggestions [ 'b', 'c' ], overload undefined
  ✅ full suggestions for filter format 'undefined', keyword '[ 'a' ]' with suggestions undefined, overload undefined
  ✅ full suggestions for filter format 'stat', keyword 'stat' with suggestions [
  'rpm',             'rof',
  'charge',          'impact',
  'handling',        'range',
  'stability',       'reload',
  'magazine',        'aimassist',
  'equipspeed',      'shieldduration',
  'velocity',        'blastradius',
  'recoildirection', 'drawtime',
  'zoom',            'airborne',
  'accuracy',        'swingspeed',
  'guardefficiency', 'guardresistance',
  'chargerate',      'guardendurance',
  'ammocapacity',    'mobility',
  'resilience',      'recovery',
  'discipline',      'intellect',
  'strength',        'total',
  'any'
], overload undefined
  ✅ full suggestions for filter format 'query', keyword 'maxstatvalue' with suggestions [
  'mobility',
  'resilience',
  'recovery',
  'discipline',
  'intellect',
  'strength',
  'total',
  'any'
], overload undefined
  ✅ full suggestions for filter format 'query', keyword 'maxstatvalue' with suggestions [
  'mobility',
  'resilience',
  'recovery',
  'discipline',
  'intellect',
  'strength',
  'total',
  'any'
], overload undefined
  ✅ full suggestions for filter format 'range', keyword 'energycapacity' with suggestions undefined, overload undefined
rangeStringToComparator
  ✅ rangeStringToComparator('<10')(8) === true
  ✅ rangeStringToComparator('<10')(10) === false
  ✅ rangeStringToComparator('>10')(10) === false
  ✅ rangeStringToComparator('>10')(15) === true
  ✅ rangeStringToComparator('<=10')(10) === true
  ✅ rangeStringToComparator('>=10')(10) === true
  ✅ rangeStringToComparator('<=10')(8) === true
  ✅ rangeStringToComparator('>=10')(15) === true
  ✅ rangeStringToComparator('<=10')(15) === false
  ✅ rangeStringToComparator('>=10')(8) === false
  ✅ rangeStringToComparator('=10')(10) === true
  ✅ rangeStringToComparator('=10')(15) === false
  ✅ rangeStringToComparator('10')(10) === true
rangeStringToComparatorWithOverloads
  ✅ rangeStringToComparatorWithOverloads('<worthy')(8) === true
  ✅ rangeStringToComparatorWithOverloads('<worthy')(10) === false
  ✅ rangeStringToComparatorWithOverloads('>10')(10) === false
  ✅ rangeStringToComparatorWithOverloads('>10')(15) === true
  ✅ rangeStringToComparatorWithOverloads('<=worthy')(10) === true
  ✅ rangeStringToComparatorWithOverloads('>=worthy')(10) === true
  ✅ rangeStringToComparatorWithOverloads('=worthy')(10) === true
  ✅ rangeStringToComparatorWithOverloads('=worthy')(15) === false
  ✅ rangeStringToComparatorWithOverloads('arrivals')(11) === true
  ✅ rangeStringToComparatorWithOverloads('arrivals')(10) === false

✅ src/app/settings/vault-grouping.test.ts

vaultWeaponGroupingSettingSelector
  ✅ returns the currently selected weapon grouping setting
vaultWeaponGroupingSelector
  ✅ returns the items ungrouped when no grouping is selected
  ✅ groups items by the currently selected weapon grouping

✅ src/app/store-stats/AccountCurrencies.test.tsx

✅ renders correctly with the basic currencies
✅ renders correctly with the basic currencies and synth stuff

✅ src/app/utils/collections.test.ts

count
  ✅ counts elements that match the predicate
objectifyArray
  ✅ keys objects by a property name that maps to an array
wrap
  ✅ negative index
  ✅ too large index
  ✅ too large index by a lot
  ✅ negative index by a lot
uniqBy
  ✅ identity
  ✅ object values
  ✅ complex func
reorder
  ✅ reorders

✅ src/app/utils/intl.test.ts

✅ should include a sorting test case for every supported DIM language
✅ localizedSorter: en
✅ localizedSorter: de
✅ localizedSorter: ko
✅ localizedSorter: ja
✅ localizedSorter: es
✅ localizedSorter: es-mx
✅ localizedSorter: fr
✅ localizedSorter: it
✅ localizedSorter: pl
✅ localizedSorter: pt-br
✅ localizedSorter: ru
✅ localizedSorter: zh-chs
✅ localizedSorter: zh-cht
✅ should include an include test case for every supported DIM language
✅ localizedIncludes("en", "bar")("foobar") === true
✅ localizedIncludes("en", "😀")("Laughing 😀!!") === true
✅ localizedIncludes("en", "�")("Laughing 😀!!") === true
✅ localizedIncludes("en", "👨‍👩‍👧")("👨‍👩‍👧‍👦") === true
✅ localizedIncludes("en", "föo")("foobar") === true
✅ localizedIncludes("en", "Föo")("foobar") === true
✅ localizedIncludes("de", "föo")("foobar") === false
✅ localizedIncludes("ko", "가")("하가") === true
✅ localizedIncludes("ja", "かさ")("あかさ赤け") === true
✅ localizedIncludes("es", "ño")("niño") === true
✅ localizedIncludes("es-mx", "ño")("niño") === true
✅ localizedIncludes("fr", "bar")("foobar") === true
✅ localizedIncludes("it", "bar")("foobar") === true
✅ localizedIncludes("pl", "bar")("foobar") === true
✅ localizedIncludes("pt-br", "bar")("foobar") === true
✅ localizedIncludes("ru", "bar")("foobar") === true
✅ localizedIncludes("zh-chs", "bar")("foobar") === true
✅ localizedIncludes("zh-cht", "bar")("foobar") === true

✅ src/app/utils/memoize.test.ts

weakMemoize
  ✅ caches results of computation

✅ src/app/utils/promises.test.ts

dedupePromise
  ✅ caches inflight promises

✅ src/app/utils/time.test.ts

✅ timerDurationFromMs(1000) === "0:00:01"
✅ timerDurationFromMs(0) === "0:00:00"
✅ timerDurationFromMs(279241234) === "3:05:34:01"
✅ timerDurationFromMs(20041234) === "5:34:01"
✅ timerDurationFromMs(1000) === "0:01"
✅ timerDurationFromMs(0) === "0:00"
✅ timerDurationFromMs(279241234) === "3:05:34:01.234"
✅ timerDurationFromMs(20041234) === "5:34:01.234"
english localization
  ✅ i15dDurationFromMs(1000) === "0:00"
  ✅ i15dDurationFromMs(0) === "0:00"
  ✅ i15dDurationFromMs(86400000) === "1 Day 0:00"
  ✅ i15dDurationFromMs(279241234) === "3 Days 5:34"
  ✅ i15dDurationFromMs(20041234) === "5:34"
  ✅ i15dDurationFromMs(1000) === "0:00"
  ✅ i15dDurationFromMs(0) === "0:00"
  ✅ i15dDurationFromMs(86400000) === "1d 0:00"
  ✅ i15dDurationFromMs(279241234) === "3d 5:34"
  ✅ i15dDurationFromMs(20041234) === "5:34"
  ✅ i15dDurationFromMs(1000) === "0:00:01"
  ✅ i15dDurationFromMs(0) === "0:00:00"
  ✅ i15dDurationFromMs(279241234) === "3 Days 5:34:01"
  ✅ i15dDurationFromMs(20041234) === "5:34:01"
japanese localization
  ✅ i15dDurationFromMs(1000) === "0:00"
  ✅ i15dDurationFromMs(0) === "0:00"
  ✅ i15dDurationFromMs(86400000) === "1日 0:00"
  ✅ i15dDurationFromMs(279241234) === "3日間 5:34"
  ✅ i15dDurationFromMs(20041234) === "5:34"
  ✅ i15dDurationFromMs(1000) === "0:00"
  ✅ i15dDurationFromMs(0) === "0:00"
  ✅ i15dDurationFromMs(86400000) === "1日 0:00"
  ✅ i15dDurationFromMs(279241234) === "3日間 5:34"
  ✅ i15dDurationFromMs(20041234) === "5:34"
  ✅ i15dDurationFromMs(1000) === "0:00:01"
  ✅ i15dDurationFromMs(0) === "0:00:00"
  ✅ i15dDurationFromMs(279241234) === "3日間 5:34:01"
  ✅ i15dDurationFromMs(20041234) === "5:34:01"

✅ src/app/utils/undo-redo-history.test.ts

✅ allows you to undo and redo loadout edits

✅ src/app/vendors/d2-vendors.test.ts

process vendors
  ✅ can process vendors without errors

✅ src/app/wishlists/wishlist-file.test.ts

✅ parse wishlist line: dimwishlist:item=-69420&perks=2682205016,2402480669#notes:Enh Over, Enh FocuFury

✅ src/browsercheck.test.ts

✅ Firefox 72: User agent Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:72.0) Gecko/20100101 Firefox/72.0, supported: true
✅ Chrome 79: User agent Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36, supported: true
✅ iOS 12: User agent Mozilla/5.0 (iPod; CPU iPhone OS 12_0 like macOS) AppleWebKit/602.1.50 (KHTML, like Gecko) Version/12.0 Mobile/14A5335d Safari/602.1.50, supported: true
✅ Edge 18: User agent Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 Edge/18.18362, supported: true
✅ Vivaldi: User agent Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36 Vivaldi/2.10, supported: true
✅ Opera: User agent Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36 OPR/65.0.3467.78, supported: true
✅ Old Chrome: User agent Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36, supported: false

✅ src/testing/precache-manifest.test.ts

✅ precache manifest