Tests/Auth.steps.ps1

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
Given 'the PSSpotify module is imported' {
    import-module $PSScriptRoot\..\PSSpotify.psd1 -Force -DisableNameChecking -Global
}

Given 'the Spotify API is (available|online)' {
    param($type, $InputData)
    $global:Data = ConvertFrom-StringData $InputData
    $global:Cred = (import-clixml $Data["CredPath"])
    $global:TokenEndpoint = $Data["TokenEndpoint"]
    $global:RootUrl = $Data["RootUrl"]
    $global:AuthorizationEndpoint = $Data["AuthorizationEndpoint"]
    $global:RedirectUri = $Data["RedirectUri"]
    $global:RefreshToken = $Data["RefreshToken"]
    $global:Perms = $Data["Perms"]
}

Given 'the Spotify API is mocked' {
    $global:Cred = New-Object PSCredential -ArgumentList 'user', (ConvertTo-SecureString 'password' -AsPlainText -Force)
    $global:TokenEndpoint = "https://localhost/MockApi/token"
    $global:RootUrl = "https://localhost/v1"
    $global:AuthorizationEndpoint = "https://localhost/authorize"
    $global:RedirectUri = "http://localhost:8001"
    $global:RefreshToken = "123"
    $global:AccessToken = "456"
    $global:AuthCode = "789"
    $global:Perms = "Scope1", "Scope2"

    mock -CommandName Invoke-RestMethod -ParameterFilter {$Uri -eq $global:TokenEndpoint} -MockWith {
        [pscustomobject]@{
            access_token  = $global:AccessToken
            refresh_token = $global:RefreshToken
            token_type    = "Bearer"
            expires_in    = 3600
            scope         = ($global:Perms -join ' ')
        }
    }

    mock Invoke-RestMethod -ParameterFilter {$Uri -eq "$global:RootUrl/me"} -MockWith { @{id = "test"} }

    mock -CommandName New-OAuthConfirmationWindow -MockWith {
        $global:AuthCode
    }
}

And 'a Spotify RefreshToken is specified' {
    $global:ConnectParams = @{
        ClientIdSecret        = $global:Cred
        RefreshToken          = $global:RefreshToken
        TokenEndpoint         = $global:TokenEndpoint
        RootAPIEndpoint       = $global:RootUrl
        RedirectUri           = $global:RedirectUri
        AuthorizationEndpoint = $global:AuthorizationEndpoint
    }
}

And 'KeepCredential is passed' {
    $global:ConnectParams.Add("KeepCredential", $true)
}

But "a Spotify RefreshToken isn't specified" {
    $global:ConnectParams = @{
        ClientIdSecret        = $global:Cred
        AuthorizationEndpoint = $global:AuthorizationEndpoint
        TokenEndpoint         = $global:TokenEndpoint
        RootAPIEndpoint       = $global:RootUrl
        RedirectUri           = $global:RedirectUri
    }
}

Then '(?<cmdletname>.+) should be called (?<times>\d+) times?' {
    param($cmdletname, $times)
    Assert-MockCalled $cmdletname -Times $times -Scope it
}

And '(?<cmdletname>.+) should be called (?<times>\d+) times?' {
    param($cmdletname, $times)
    Assert-MockCalled $cmdletname -Times $times -Scope it
}

When 'I connect to Spotify' {
    $session = Connect-Spotify @ConnectParams
}

Then 'a Spotify Session object should be returned' {
    $Session | Should -BeOfType PSSpotify.SessionInfo
}

And 'the Spotify Session should be valid' {
    $Session.headers.Authorization | should -BeLike "Bearer *"
    $Session.headers.contenttype | should -Be "application/json"
    $Session.expires -gt 0 | should -Be $true
    $Session.RefreshToken.Length -gt 0 | should -Be $true
    $Session.APIEndpoints.TokenEndpoint | should -Be $global:TokenEndpoint
    $Session.APIEndpoints.AuthorizationEndpoint | should -Be $global:AuthorizationEndpoint
    $Session.APIEndpoints.RedirectUri | should -Be $global:RedirectUri
    $Session.CurrentUser.Id | should -Not -BeNullOrEmpty
}

And 'the Spotify Session permissions should match' {
    param($Perm)
    $Session.Scope | should -BeLike "*$Perm*"
}

And 'a Spotify Credential object should be created' {
    $global:SpotifyCredential | should -Not -BeNullOrEmpty
}

When 'I assert the access token is valid' {
    $OldToken = $global:SpotifySession.Headers.Authorization
    mock Invoke-RestMethod -ParameterFilter {$Uri -eq "$global:RootUrl/me"} -MockWith { }
    $null = Assert-AuthToken -Session $global:SpotifySession
}

Then 'the access token should stay the same' {
    $OldToken -eq $global:SpotifySession.Headers.Authorization | should -Be $true
}

When 'I assert the access token is invalid' {
    $OldToken = $global:SpotifySession.Headers.Authorization
    mock Invoke-RestMethod -ParameterFilter {$Uri -eq "$global:RootUrl/me"} -MockWith { Write-Error -Exception "The access token expired" -Message '{Error:{Message: "The access token expired"}}' -ea stop }
    mock Connect-Spotify -MockWith {
        $Global:RefreshedSession = [PSSpotify.SessionInfo]@{
            Headers = @{Authorization = "Bearer 321"; "contenttype" = "application/json"}
        }
    }
    $null = Assert-AuthToken -Session $global:SpotifySession
}

Then 'the access token should be refreshed' {
    $OldToken -eq $Global:RefreshedSession.Headers.Authorization | should -Be $false
}