blob: 22054d28bd209c8e54ccb3d3620bef4cd4347667 [file] [log] [blame]
Akron33f5c672019-06-24 19:40:47 +02001use Mojo::Base -strict;
2use Test::More;
Akroncdfd9d52019-07-23 11:35:00 +02003use Test::Mojo::WithRoles 'Session';
Akron33f5c672019-06-24 19:40:47 +02004use Mojo::File qw/path/;
5use Data::Dumper;
6
7
8#####################
9# Start Fake server #
10#####################
Akron63d963b2019-07-05 15:35:51 +020011my $mount_point = '/realapi/';
Akron33f5c672019-06-24 19:40:47 +020012$ENV{KALAMAR_API} = $mount_point;
13
Akroncdfd9d52019-07-23 11:35:00 +020014my $t = Test::Mojo::WithRoles->new('Kalamar' => {
Akron33f5c672019-06-24 19:40:47 +020015 Kalamar => {
16 plugins => ['Auth']
17 },
18 'Kalamar-Auth' => {
19 client_id => 2,
20 client_secret => 'k414m4r-s3cr3t',
Akron59992122019-10-29 11:28:45 +010021 oauth2 => 1,
22 experimental_client_registration => 1
Akron33f5c672019-06-24 19:40:47 +020023 }
24});
25
26# Mount fake backend
27# Get the fixture path
28my $fixtures_path = path(Mojo::File->new(__FILE__)->dirname, '..', 'server');
29my $fake_backend = $t->app->plugin(
30 Mount => {
31 $mount_point =>
32 $fixtures_path->child('mock.pl')
33 }
34);
35# Configure fake backend
Akroncdfd9d52019-07-23 11:35:00 +020036my $fake_backend_app = $fake_backend->pattern->defaults->{app};
37
38# Set general app logger for simplicity
39$fake_backend_app->log($t->app->log);
40
41my $access_token = $fake_backend_app->get_token('access_token');
42my $refresh_token = $fake_backend_app->get_token('refresh_token');
43my $access_token_2 = $fake_backend_app->get_token('access_token_2');
44my $refresh_token_2 = $fake_backend_app->get_token('refresh_token_2');
45
46# Some routes to modify the session
47# This expires the session
48$t->app->routes->get('/x/expire')->to(
49 cb => sub {
50 my $c = shift;
51 $c->session(auth_exp => 0);
52 return $c->render(text => 'okay')
53 }
54);
55
56# This expires the session and removes the refresh token
57$t->app->routes->get('/x/expire-no-refresh')->to(
58 cb => sub {
59 my $c = shift;
60 $c->session(auth_exp => 0);
61 delete $c->session->{auth_r};
62 return $c->render(text => 'okay')
63 }
64);
65
66# This sets an invalid token
67$t->app->routes->get('/x/invalid')->to(
68 cb => sub {
69 my $c = shift;
70 $c->session(auth_exp => time + 1000);
71 $c->session(auth_r => $refresh_token_2);
72 $c->session(auth => 'Bearer inv4lid');
73 return $c->render(text => 'okay')
74 }
75);
76
77
78# This sets an invalid token
79$t->app->routes->get('/x/invalid-no-refresh')->to(
80 cb => sub {
81 my $c = shift;
82 $c->session(auth_exp => time + 1000);
83 delete $c->session->{auth_r};
84 $c->session(auth => 'Bearer inv4lid');
85 return $c->render(text => 'okay')
86 }
87);
88
89# This sets an invalid refresh token
90$t->app->routes->get('/x/expired-with-wrong-refresh')->to(
91 cb => sub {
92 my $c = shift;
93 $c->session(auth_exp => 0);
94 $c->session(auth => 'Bearer inv4lid');
95 $c->session(auth_r => 'inv4lid');
96 return $c->render(text => 'okay')
97 }
98);
99
Akronbc6b3f22021-01-13 14:53:12 +0100100my $q = qr!(?:\"|")!;
Akron33f5c672019-06-24 19:40:47 +0200101
Akron63d963b2019-07-05 15:35:51 +0200102$t->get_ok('/realapi/v1.0')
Akron33f5c672019-06-24 19:40:47 +0200103 ->status_is(200)
104 ->content_is('Fake server available');
105
106$t->get_ok('/?q=Baum')
107 ->status_is(200)
108 ->text_like('h1 span', qr/KorAP: Find .Baum./i)
109 ->text_like('#total-results', qr/\d+$/)
Akronbc6b3f22021-01-13 14:53:12 +0100110 ->content_like(qr/${q}authorized${q}:null/)
Akron33f5c672019-06-24 19:40:47 +0200111 ->element_exists_not('div.button.top a')
112 ->element_exists_not('aside.active')
113 ->element_exists_not('aside.off')
114 ;
115
116$t->get_ok('/')
117 ->status_is(200)
Akrone208d302020-11-28 11:14:50 +0100118 ->element_exists('form[action=/user/login] input[name=handle]')
Akron33f5c672019-06-24 19:40:47 +0200119 ->element_exists('aside.active')
120 ->element_exists_not('aside.off')
121 ;
122
Akron3e0fdc12020-05-15 16:17:21 +0200123# Test for bug with long password
124$t->post_ok('/user/login' => form => {
Akrone208d302020-11-28 11:14:50 +0100125 handle => 'test',
Akron3e0fdc12020-05-15 16:17:21 +0200126 pwd => 'kjskjhndkjndqknaskjnakjdnkjdankajdnkjdsankjdsakjdfkjahzroiuqzriudjoijdmlamdlkmdsalkmdl' })
127 ->status_is(302)
128 ->header_is('Location' => '/');
129
Akrone208d302020-11-28 11:14:50 +0100130$t->post_ok('/user/login' => form => { handle => 'test', pwd => 'fail' })
Akron33f5c672019-06-24 19:40:47 +0200131 ->status_is(302)
132 ->header_is('Location' => '/');
133
134$t->get_ok('/')
135 ->status_is(200)
136 ->element_exists('div.notify-error')
137 ->text_is('div.notify-error', 'Bad CSRF token')
Akrone208d302020-11-28 11:14:50 +0100138 ->element_exists('input[name=handle][value=test]')
Akron33f5c672019-06-24 19:40:47 +0200139 ->element_exists_not('div.button.top a')
140 ;
141
Akrone208d302020-11-28 11:14:50 +0100142$t->post_ok('/user/login' => form => { handle => 'test', pwd => 'pass' })
Akron33f5c672019-06-24 19:40:47 +0200143 ->status_is(302)
144 ->header_is('Location' => '/');
145
146my $csrf = $t->get_ok('/')
147 ->status_is(200)
148 ->element_exists('div.notify-error')
149 ->text_is('div.notify-error', 'Bad CSRF token')
150 ->element_exists_not('div.button.top a')
151 ->tx->res->dom->at('input[name=csrf_token]')->attr('value')
152 ;
153
154$t->post_ok('/user/login' => form => {
Akrone208d302020-11-28 11:14:50 +0100155 handle => 'test',
Akron33f5c672019-06-24 19:40:47 +0200156 pwd => 'ldaperr',
157 csrf_token => $csrf
158})
159 ->status_is(302)
160 ->content_is('')
161 ->header_is('Location' => '/');
162
163$csrf = $t->get_ok('/')
164 ->status_is(200)
165 ->element_exists('div.notify-error')
166 ->text_is('div.notify-error', '2022: LDAP Authentication failed due to unknown user or password!')
Akrone208d302020-11-28 11:14:50 +0100167 ->element_exists('input[name=handle][value=test]')
Akron33f5c672019-06-24 19:40:47 +0200168 ->element_exists_not('div.button.top a')
Akron3b3c7af2020-05-15 16:23:55 +0200169 ->element_exists_not('div.notify-success')
Akron33f5c672019-06-24 19:40:47 +0200170 ->tx->res->dom->at('input[name=csrf_token]')->attr('value')
171 ;
172
173$t->post_ok('/user/login' => form => {
Akrone208d302020-11-28 11:14:50 +0100174 handle => 'test',
Akron33f5c672019-06-24 19:40:47 +0200175 pwd => 'unknown',
176 csrf_token => $csrf
177})
178 ->status_is(302)
179 ->content_is('')
180 ->header_is('Location' => '/');
181
182$csrf = $t->get_ok('/')
183 ->status_is(200)
184 ->element_exists('div.notify-error')
Akron8bbbecf2019-07-01 18:57:30 +0200185 ->text_is('div.notify-error', '2022: LDAP Authentication failed due to unknown user or password!')
Akrone208d302020-11-28 11:14:50 +0100186 ->element_exists('input[name=handle][value=test]')
Akron33f5c672019-06-24 19:40:47 +0200187 ->element_exists_not('div.button.top a')
188 ->tx->res->dom->at('input[name=csrf_token]')->attr('value')
189 ;
190
191$t->post_ok('/user/login' => form => {
Akrone208d302020-11-28 11:14:50 +0100192 handle => 'test',
Akron33f5c672019-06-24 19:40:47 +0200193 pwd => 'pass',
194 csrf_token => $csrf
195})
196 ->status_is(302)
197 ->content_is('')
198 ->header_is('Location' => '/');
199
200$t->get_ok('/')
201 ->status_is(200)
202 ->element_exists_not('div.notify-error')
203 ->element_exists('div.notify-success')
204 ->text_is('div.notify-success', 'Login successful')
205 ->element_exists('aside.off')
206 ->element_exists_not('aside.active')
207 ;
208
Akron33f5c672019-06-24 19:40:47 +0200209# Now the user is logged in and should be able to
210# search with authorization
211$t->get_ok('/?q=Baum')
212 ->status_is(200)
Akron4cefe1f2019-09-04 10:11:28 +0200213 ->session_has('/auth')
214 ->session_is('/auth', 'Bearer ' . $access_token)
215 ->session_is('/auth_r', $refresh_token)
216 ->session_is('/user', 'test')
Akron33f5c672019-06-24 19:40:47 +0200217 ->text_like('h1 span', qr/KorAP: Find .Baum./i)
218 ->text_like('#total-results', qr/\d+$/)
219 ->element_exists_not('div.notify-error')
Akronbc6b3f22021-01-13 14:53:12 +0100220 ->content_like(qr/${q}authorized${q}:${q}yes${q}/)
Akron33f5c672019-06-24 19:40:47 +0200221 ->element_exists('div.button.top a')
222 ->element_exists('div.button.top a.logout[title~="test"]')
223 ;
224
Akron27031aa2020-04-28 14:57:10 +0200225$t->get_ok('/?q=Paum')
226 ->status_is(200)
227 ->text_like('h1 span', qr/KorAP: Find .Paum./i)
228 ->text_is('#total-results', '')
Akronbc6b3f22021-01-13 14:53:12 +0100229 ->content_like(qr/${q}authorized${q}:${q}yes${q}/)
Akron27031aa2020-04-28 14:57:10 +0200230 ->element_exists_not('p.hint')
231 ;
232
233
Akron33f5c672019-06-24 19:40:47 +0200234# Logout
235$t->get_ok('/user/logout')
236 ->status_is(302)
Akron4cefe1f2019-09-04 10:11:28 +0200237 ->session_hasnt('/auth')
238 ->session_hasnt('/auth_r')
239 ->session_hasnt('/user')
Akron33f5c672019-06-24 19:40:47 +0200240 ->header_is('Location' => '/');
241
242$t->get_ok('/')
243 ->status_is(200)
244 ->element_exists_not('div.notify-error')
245 ->element_exists('div.notify-success')
246 ->text_is('div.notify-success', 'Logout successful')
Akrone208d302020-11-28 11:14:50 +0100247 ->element_exists("input[name=handle]")
248 ->element_exists("input[name=handle][value=test]")
Akron33f5c672019-06-24 19:40:47 +0200249 ;
250
251$t->get_ok('/?q=Baum')
252 ->status_is(200)
253 ->text_like('h1 span', qr/KorAP: Find .Baum./i)
254 ->text_like('#total-results', qr/\d+$/)
Akronbc6b3f22021-01-13 14:53:12 +0100255 ->content_like(qr/${q}authorized${q}:null/)
Akron33f5c672019-06-24 19:40:47 +0200256 ;
257
Akron27031aa2020-04-28 14:57:10 +0200258$t->get_ok('/?q=Paum')
259 ->status_is(200)
260 ->text_like('h1 span', qr/KorAP: Find .Paum./i)
261 ->text_is('#total-results', '')
Akronbc6b3f22021-01-13 14:53:12 +0100262 ->content_like(qr/${q}authorized${q}:null/)
Akron27031aa2020-04-28 14:57:10 +0200263 ->text_is('p.hint', 'Maybe you need to log in first?')
264 ;
265
266
Akron33f5c672019-06-24 19:40:47 +0200267# Get redirect
268my $fwd = $t->get_ok('/?q=Baum&ql=poliqarp')
269 ->status_is(200)
270 ->element_exists_not('div.notify-error')
271 ->tx->res->dom->at('input[name=fwd]')->attr('value')
272 ;
273
274is($fwd, '/?q=Baum&ql=poliqarp', 'Redirect is valid');
275
276$t->post_ok('/user/login' => form => {
Akrone208d302020-11-28 11:14:50 +0100277 handle => 'test',
Akron33f5c672019-06-24 19:40:47 +0200278 pwd => 'pass',
279 csrf_token => $csrf,
280 fwd => 'http://bad.example.com/test'
281})
282 ->status_is(302)
283 ->header_is('Location' => '/');
284
285$t->get_ok('/')
286 ->status_is(200)
287 ->element_exists('div.notify-error')
288 ->element_exists_not('div.notify-success')
289 ->text_is('div.notify-error', 'Redirect failure')
290 ;
291
292$t->post_ok('/user/login' => form => {
Akrone208d302020-11-28 11:14:50 +0100293 handle => 'test',
Akron33f5c672019-06-24 19:40:47 +0200294 pwd => 'pass',
295 csrf_token => $csrf,
296 fwd => $fwd
297})
298 ->status_is(302)
299 ->header_is('Location' => '/?q=Baum&ql=poliqarp');
300
Akron8bbbecf2019-07-01 18:57:30 +0200301$t->get_ok('/?q=Baum&ql=poliqarp')
302 ->status_is(200)
303 ->element_exists_not('div.notify-error')
304 ->element_exists('div.notify-success')
305 ->text_is('div.notify-success', 'Login successful')
Akroncdfd9d52019-07-23 11:35:00 +0200306 ->session_has('/auth')
307 ->session_is('/auth', 'Bearer ' . $access_token)
308 ->session_is('/auth_r', $refresh_token)
309 ->header_isnt('X-Kalamar-Cache', 'true')
Akron8bbbecf2019-07-01 18:57:30 +0200310 ;
311
Akroncdfd9d52019-07-23 11:35:00 +0200312# Expire the session
313# (makes the token be marked as expired - though it isn't serverside)
314$t->get_ok('/x/expire')
Akron8bbbecf2019-07-01 18:57:30 +0200315 ->status_is(200)
Akroncdfd9d52019-07-23 11:35:00 +0200316 ->content_is('okay')
317 ;
318
319## It may be a problem, but the cache is still valid
320$t->get_ok('/?q=Baum')
321 ->status_is(200)
322 ->text_like('h1 span', qr/KorAP: Find .Baum./i)
323 ->text_like('#total-results', qr/\d+$/)
Akronbc6b3f22021-01-13 14:53:12 +0100324 ->content_like(qr/${q}authorized${q}:${q}yes${q}/)
Akroncdfd9d52019-07-23 11:35:00 +0200325 ->header_is('X-Kalamar-Cache', 'true')
326 ;
327
328# Query without partial cache (unfortunately) (but no total results)
329$t->get_ok('/?q=baum&cutoff=true')
330 ->status_is(200)
331 ->session_is('/auth', 'Bearer ' . $access_token_2)
332 ->session_is('/auth_r', $refresh_token_2)
333 ->text_is('#error','')
334 ->text_is('title', 'KorAP: Find »baum« with Poliqarp')
335 ->element_exists('meta[name="DC.title"][content="KorAP: Find »baum« with Poliqarp"]')
336 ->element_exists('body[itemscope][itemtype="http://schema.org/SearchResultsPage"]')
Akronbc6b3f22021-01-13 14:53:12 +0100337 ->content_like(qr/${q}authorized${q}:${q}yes${q}/)
Akroncdfd9d52019-07-23 11:35:00 +0200338 ->header_isnt('X-Kalamar-Cache', 'true')
Akronbc6b3f22021-01-13 14:53:12 +0100339 ->content_like(qr!${q}cutOff${q}:true!)
Akroncdfd9d52019-07-23 11:35:00 +0200340 ->element_exists_not('#total-results')
341 ;
342
343# Expire the session and remove the refresh option
344$t->get_ok('/x/expire-no-refresh')
345 ->status_is(200)
346 ->content_is('okay')
347 ;
348
349$t->app->defaults(no_cache => 1);
350
351
352$t->get_ok('/x/invalid-no-refresh')
353 ->status_is(200)
354 ->content_is('okay')
355 ;
356
357# Query without cache
358# The token is invalid and can't be refreshed!
359$t->get_ok('/?q=baum&cutoff=true')
Akron3c390c42020-03-30 09:06:21 +0200360 ->status_is(400)
Akroncdfd9d52019-07-23 11:35:00 +0200361 ->session_hasnt('/auth')
362 ->session_hasnt('/auth_r')
363 ->text_is('#error','')
364 ->text_is('div.notify-error','Access token invalid')
365 ->text_is('title', 'KorAP: Find »baum« with Poliqarp')
366 ->element_exists('meta[name="DC.title"][content="KorAP: Find »baum« with Poliqarp"]')
367 ->element_exists('body[itemscope][itemtype="http://schema.org/SearchResultsPage"]')
Akronbc6b3f22021-01-13 14:53:12 +0100368 ->content_unlike(qr/${q}authorized${q}:${q}yes${q}/)
Akroncdfd9d52019-07-23 11:35:00 +0200369 ->header_isnt('X-Kalamar-Cache', 'true')
370 ->element_exists('p.no-results')
371 ;
372
373$t->get_ok('/x/invalid')
374 ->status_is(200)
375 ->content_is('okay')
376 ;
377
378# Query without cache
379# The token is invalid and can't be refreshed!
380$t->get_ok('/?q=baum&cutoff=true')
381 ->status_is(200)
382 ->session_is('/auth', 'Bearer ' . $access_token_2)
383 ->session_is('/auth_r', $refresh_token_2)
384 ->text_is('#error','')
385 ->element_exists_not('div.notify-error','Access token invalid')
386 ->text_is('title', 'KorAP: Find »baum« with Poliqarp')
387 ->element_exists('meta[name="DC.title"][content="KorAP: Find »baum« with Poliqarp"]')
388 ->element_exists('body[itemscope][itemtype="http://schema.org/SearchResultsPage"]')
Akronbc6b3f22021-01-13 14:53:12 +0100389 ->content_like(qr/${q}authorized${q}:${q}yes${q}/)
Akroncdfd9d52019-07-23 11:35:00 +0200390 ->header_isnt('X-Kalamar-Cache', 'true')
391 ->element_exists_not('p.no-results')
Akron8bbbecf2019-07-01 18:57:30 +0200392 ;
393
Akron33f5c672019-06-24 19:40:47 +0200394
Akroncdfd9d52019-07-23 11:35:00 +0200395$t->get_ok('/x/expired-with-wrong-refresh')
396 ->status_is(200)
397 ->content_is('okay')
398 ;
Akron4796e002019-07-05 10:13:15 +0200399
Akron4796e002019-07-05 10:13:15 +0200400
Akroncdfd9d52019-07-23 11:35:00 +0200401# The token is invalid and can't be refreshed!
Akron59992122019-10-29 11:28:45 +0100402$csrf = $t->get_ok('/?q=baum&cutoff=true')
Akron3c390c42020-03-30 09:06:21 +0200403 ->status_is(400)
Akroncdfd9d52019-07-23 11:35:00 +0200404 ->session_hasnt('/auth')
405 ->session_hasnt('/auth_r')
406 ->text_is('#error','')
407 ->text_is('div.notify-error','Refresh token is expired')
408 ->text_is('title', 'KorAP: Find »baum« with Poliqarp')
Akronbc6b3f22021-01-13 14:53:12 +0100409 ->content_unlike(qr/${q}authorized${q}:${q}yes${q}/)
Akroncdfd9d52019-07-23 11:35:00 +0200410 ->element_exists('p.no-results')
Akron59992122019-10-29 11:28:45 +0100411 ->tx->res->dom->at('input[name="csrf_token"]')
412 ->attr('value')
Akroncdfd9d52019-07-23 11:35:00 +0200413 ;
Akron4796e002019-07-05 10:13:15 +0200414
Akron59992122019-10-29 11:28:45 +0100415# Login:
416$t->post_ok('/user/login' => form => {
Akrone208d302020-11-28 11:14:50 +0100417 handle => 'test',
Akron59992122019-10-29 11:28:45 +0100418 pwd => 'pass',
419 csrf_token => $csrf
420})
421 ->status_is(302)
422 ->content_is('')
423 ->header_is('Location' => '/');
424
425$t->get_ok('/')
426 ->status_is(200)
427 ->element_exists_not('div.notify-error')
428 ->element_exists('div.notify-success')
429 ->text_is('div.notify-success', 'Login successful')
430 ->element_exists('aside.off')
431 ->element_exists_not('aside.active')
432 ;
433
434$t->get_ok('/settings/oauth')
435 ->text_is('form.form-table legend', 'Register new client application')
436 ->attr_is('form.oauth-register','action', '/settings/oauth/register')
Akron1a9d5be2020-03-19 17:28:33 +0100437 ->element_exists('ul.client-list')
438 ->element_exists_not('ul.client-list > li')
439# ->text_is('ul.client-list > li > span.client-name', 'R statistical computing tool ')
440# ->text_is('ul.client-list > li > span.client-desc', 'R is a free software environment for statistical computing and graphics.')
441# ->text_is('ul.client-list > li > span.client-url a', 'https://www.r-project.org/')
442# ->text_is('ul.client-list > li a.client-unregister', 'Unregister')
443# ->attr_is('ul.client-list > li a.client-unregister', 'href', '/settings/oauth/unregister/9aHsGW6QflV13ixNpez?name=R+statistical+computing+tool')
Akron59992122019-10-29 11:28:45 +0100444 ;
Akron59992122019-10-29 11:28:45 +0100445$csrf = $t->post_ok('/settings/oauth/register' => form => {
446 name => 'MyApp',
447 type => 'PUBLIC',
448 desc => 'This is my application'
449})
450 ->text_is('div.notify-error', 'Bad CSRF token')
451 ->tx->res->dom->at('input[name="csrf_token"]')
452 ->attr('value')
453 ;
454
455$t->post_ok('/settings/oauth/register' => form => {
456 name => 'MyApp',
457 type => 'CONFIDENTIAL',
458 desc => 'This is my application',
459 csrf_token => $csrf
460})
461 ->status_is(200)
462 ->element_exists('div.notify-success')
463 ->text_is('legend', 'Client Credentials')
464 ->text_is('label[for=client_id]', 'ID of the client application')
465 ->element_exists('input[name=client_id][readonly][value]')
466 ->element_exists('input[name=client_secret][readonly][value]')
467 ;
Akron4796e002019-07-05 10:13:15 +0200468
Akron1a9d5be2020-03-19 17:28:33 +0100469$t->get_ok('/settings/oauth')
470 ->text_is('form.form-table legend', 'Register new client application')
471 ->attr_is('form.oauth-register','action', '/settings/oauth/register')
Akron17de86e2020-04-16 16:03:40 +0200472 ->text_is('ul.client-list > li > span.client-name a', 'MyApp')
Akron1a9d5be2020-03-19 17:28:33 +0100473 ->text_is('ul.client-list > li > span.client-desc', 'This is my application')
474 ->text_is('ul.client-list > li > span.client-url a', '')
Akron17de86e2020-04-16 16:03:40 +0200475 ;
476
477$t->get_ok('/settings/oauth/client/fCBbQkA2NDA3MzM1Yw==')
478 ->status_is(200)
479 ->text_is('form ul.client-list > li.client > span.client-name', 'MyApp')
480 ->text_is('form ul.client-list > li.client > span.client-desc', 'This is my application')
481 ->text_is('a.client-unregister', 'Unregister')
482 ->attr_is('a.client-unregister', 'href', '/settings/oauth/unregister/fCBbQkA2NDA3MzM1Yw==?name=MyApp')
Akron1a9d5be2020-03-19 17:28:33 +0100483 ;
484
485$csrf = $t->get_ok('/settings/oauth/unregister/fCBbQkA2NDA3MzM1Yw==?name=MyApp')
486 ->content_like(qr!Do you really want to unregister \<span class="client-name"\>MyApp\<\/span\>?!)
487 ->attr_is('form.form-table input[name=client-id]', 'value', 'fCBbQkA2NDA3MzM1Yw==')
488 ->attr_is('form.form-table input[name=client-name]', 'value', 'MyApp')
489 ->tx->res->dom->at('input[name="csrf_token"]')
490 ->attr('value')
491 ;
492
493$t->post_ok('/settings/oauth/unregister' => form => {
494 'client-name' => 'MyApp',
495 'client-id' => 'xxxx==',
496 'csrf_token' => $csrf
497})->status_is(302)
498 ->content_is('')
499 ->header_is('Location' => '/settings/oauth')
500 ;
501
502$t->get_ok('/settings/oauth')
503 ->text_is('form.form-table legend', 'Register new client application')
504 ->attr_is('form.oauth-register','action', '/settings/oauth/register')
505 ->element_exists('ul.client-list > li')
506 ->text_is('div.notify', 'Unknown client with xxxx==.')
507 ;
508
509$t->post_ok('/settings/oauth/unregister' => form => {
510 'client-name' => 'MyApp',
511 'client-id' => 'fCBbQkA2NDA3MzM1Yw==',
512 'csrf_token' => $csrf
513})->status_is(302)
514 ->content_is('')
515 ->header_is('Location' => '/settings/oauth')
516 ;
517
518$t->get_ok('/settings/oauth')
519 ->text_is('form.form-table legend', 'Register new client application')
520 ->attr_is('form.oauth-register','action', '/settings/oauth/register')
521 ->element_exists_not('ul.client-list > li')
522 ->text_is('div.notify-success', 'Successfully deleted MyApp')
523 ;
524
Akron33f5c672019-06-24 19:40:47 +0200525done_testing;
526__END__