-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfeed.xml
1933 lines (1517 loc) · 227 KB
/
feed.xml
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
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.8.3">Jekyll</generator><link href="http://0.0.0.0:4000/feed.xml" rel="self" type="application/atom+xml" /><link href="http://0.0.0.0:4000/" rel="alternate" type="text/html" /><updated>2025-01-27T10:19:44+01:00</updated><id>http://0.0.0.0:4000/feed.xml</id><title type="html">Citrus Integration Tests</title><subtitle>Automated integration tests for message protocols and data formats that you require</subtitle><entry><title type="html">XML samples</title><link href="http://0.0.0.0:4000/samples/overview/xml/" rel="alternate" type="text/html" title="XML samples" /><published>2024-01-23T00:00:00+01:00</published><updated>2024-01-23T00:00:00+01:00</updated><id>http://0.0.0.0:4000/samples/overview/samples-xml</id><content type="html" xml:base="http://0.0.0.0:4000/samples/overview/xml/"><p>Read about the XML validation support in the <a href="https://citrusframework.org/citrus/reference/html/#xml-message-validation">reference guide</a></p></content><author><name></name></author></entry><entry><title type="html">Soap WS samples</title><link href="http://0.0.0.0:4000/samples/overview/soap/" rel="alternate" type="text/html" title="Soap WS samples" /><published>2024-01-23T00:00:00+01:00</published><updated>2024-01-23T00:00:00+01:00</updated><id>http://0.0.0.0:4000/samples/overview/samples-soap</id><content type="html" xml:base="http://0.0.0.0:4000/samples/overview/soap/"><p>Read about the SOAP WebServices support in the <a href="https://citrusframework.org/citrus/reference/html/#soap-webservices">reference guide</a></p></content><author><name></name></author></entry><entry><title type="html">Http samples</title><link href="http://0.0.0.0:4000/samples/overview/http/" rel="alternate" type="text/html" title="Http samples" /><published>2024-01-23T00:00:00+01:00</published><updated>2024-01-23T00:00:00+01:00</updated><id>http://0.0.0.0:4000/samples/overview/samples-http</id><content type="html" xml:base="http://0.0.0.0:4000/samples/overview/http/"><p>Read about the Http support in the <a href="https://citrusframework.org/citrus/reference/html#http-rest">reference guide</a></p></content><author><name></name></author></entry><entry><title type="html">Ftp samples</title><link href="http://0.0.0.0:4000/samples/overview/ftp/" rel="alternate" type="text/html" title="Ftp samples" /><published>2024-01-23T00:00:00+01:00</published><updated>2024-01-23T00:00:00+01:00</updated><id>http://0.0.0.0:4000/samples/overview/samples-ftp</id><content type="html" xml:base="http://0.0.0.0:4000/samples/overview/ftp/"><p>Read about the Ftp/Sftp support in the <a href="https://citrusframework.org/citrus/reference/html/#ftp">reference guide</a></p></content><author><name></name></author></entry><entry><title type="html">JBang sample</title><link href="http://0.0.0.0:4000/samples/jbang/" rel="alternate" type="text/html" title="JBang sample" /><published>2024-01-23T00:00:00+01:00</published><updated>2024-01-23T00:00:00+01:00</updated><id>http://0.0.0.0:4000/samples/sample-jbang</id><content type="html" xml:base="http://0.0.0.0:4000/samples/jbang/"><p>You can easily create and run Citrus tests with <a href="https://www.jbang.dev/">JBang</a>.
The JBang tool support in Citrus is described in more detail in <a href="https://citrusframework.org/citrus/reference/html#runtime-jbang">reference guide</a></p>
<p>Running Citrus via JBang does not require any project setup which is a fantastic match for fast prototyping of integration tests.
The JBang command will automatically set up everything you need to run the Citrus test.
This means you can run your test case sources directly from your command line.</p>
<p>To initialize a test you can run the script <code class="highlighter-rouge">citrus@citrusframework/citrus</code> with the <code class="highlighter-rouge">init</code> command as follows:</p>
<p><em>Initialize my-test.yaml</em></p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>jbang citrus@citrusframework/citrus init my-test.yaml
</code></pre></div></div>
<p>The command above uses the JBang catalog <code class="highlighter-rouge">citrus@citrusframework/citrus</code> located on the <a href="https://github.com/citrusframework/citrus">Citrus GitHub repository</a>.
JBang will automatically resolve all dependencies and execute the command line script tool.
This initializes the Citrus test file.
You will find the created test source file in the current directory.</p>
<p><em>my-test.yaml</em></p>
<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">name</span><span class="pi">:</span> <span class="s">my-test</span>
<span class="na">author</span><span class="pi">:</span> <span class="s">Citrus</span>
<span class="na">status</span><span class="pi">:</span> <span class="s">FINAL</span>
<span class="na">description</span><span class="pi">:</span> <span class="s">Sample test in YAML</span>
<span class="na">variables</span><span class="pi">:</span>
<span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">message</span>
<span class="na">value</span><span class="pi">:</span> <span class="s">Citrus rocks!</span>
<span class="na">actions</span><span class="pi">:</span>
<span class="pi">-</span> <span class="na">echo</span><span class="pi">:</span>
<span class="na">message</span><span class="pi">:</span> <span class="s2">"</span><span class="s">${message}"</span>
</code></pre></div></div>
<p>The JBang script is able to initialize any supported Citrus test domain specific language <code class="highlighter-rouge">.java</code>, <code class="highlighter-rouge">.xml</code>, <code class="highlighter-rouge">.yaml</code>, <code class="highlighter-rouge">.groovy</code> or <code class="highlighter-rouge">.feature</code>.</p>
<p>You can now run this test source file without any prior project setup using Citrus JBang:</p>
<p><em>Run my-test.yaml</em></p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>jbang citrus@citrusframework/citrus run my-test.yaml
</code></pre></div></div>
<p>The command output will be like this:</p>
<p><em>Output</em></p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>INFO 53887 <span class="nt">---</span> <span class="o">[</span> main] citrusframework.testng.TestNGEngine : Running <span class="nb">test source </span>my-test.yaml
INFO 53887 <span class="nt">---</span> <span class="o">[</span> main] org.testng.internal.Utils : <span class="o">[</span>TestNG] Running:
INFO 53887 <span class="nt">---</span> <span class="o">[</span> main] rusframework.report.LoggingReporter : .__ __
INFO 53887 <span class="nt">---</span> <span class="o">[</span> main] rusframework.report.LoggingReporter : ____ |__|/ |________ __ __ ______
INFO 53887 <span class="nt">---</span> <span class="o">[</span> main] rusframework.report.LoggingReporter : _/ ___<span class="se">\|</span> <span class="se">\ </span> __<span class="se">\_</span> __ <span class="se">\ </span> | <span class="se">\/</span> ___/
INFO 53887 <span class="nt">---</span> <span class="o">[</span> main] rusframework.report.LoggingReporter : <span class="se">\ </span> <span class="se">\_</span>__| <span class="o">||</span> | | | <span class="se">\/</span> | /<span class="se">\_</span>__ <span class="se">\ </span>
INFO 53887 <span class="nt">---</span> <span class="o">[</span> main] rusframework.report.LoggingReporter : <span class="se">\_</span>__ <span class="o">&gt;</span>__||__| |__| |____//____ <span class="o">&gt;</span>
INFO 53887 <span class="nt">---</span> <span class="o">[</span> main] rusframework.report.LoggingReporter : <span class="se">\/</span> <span class="se">\/</span>
INFO 53887 <span class="nt">---</span> <span class="o">[</span> main] rusframework.report.LoggingReporter :
INFO 53887 <span class="nt">---</span> <span class="o">[</span> main] rusframework.report.LoggingReporter : C I T R U S T E S T S 4.5.2
INFO 53887 <span class="nt">---</span> <span class="o">[</span> main] rusframework.report.LoggingReporter :
INFO 53887 <span class="nt">---</span> <span class="o">[</span> main] rusframework.report.LoggingReporter : <span class="nt">------------------------------------------------------------------------</span>
INFO 53887 <span class="nt">---</span> <span class="o">[</span> main] .citrusframework.actions.EchoAction : Citrus rocks!
INFO 53887 <span class="nt">---</span> <span class="o">[</span> main] rusframework.report.LoggingReporter :
INFO 53887 <span class="nt">---</span> <span class="o">[</span> main] rusframework.report.LoggingReporter : TEST SUCCESS my-test <span class="o">(</span>org.citrusframework<span class="o">)</span>
INFO 53887 <span class="nt">---</span> <span class="o">[</span> main] rusframework.report.LoggingReporter : <span class="nt">------------------------------------------------------------------------</span>
INFO 53887 <span class="nt">---</span> <span class="o">[</span> main] rusframework.report.LoggingReporter :
INFO 53887 <span class="nt">---</span> <span class="o">[</span> main] rusframework.report.LoggingReporter :
INFO 53887 <span class="nt">---</span> <span class="o">[</span> main] rusframework.report.LoggingReporter : CITRUS TEST RESULTS
INFO 53887 <span class="nt">---</span> <span class="o">[</span> main] rusframework.report.LoggingReporter :
INFO 53887 <span class="nt">---</span> <span class="o">[</span> main] rusframework.report.LoggingReporter : SUCCESS <span class="o">(</span> 3 ms<span class="o">)</span> my-test
INFO 53887 <span class="nt">---</span> <span class="o">[</span> main] rusframework.report.LoggingReporter :
INFO 53887 <span class="nt">---</span> <span class="o">[</span> main] rusframework.report.LoggingReporter : TOTAL: 1
INFO 53887 <span class="nt">---</span> <span class="o">[</span> main] rusframework.report.LoggingReporter : SUCCESS: 1 <span class="o">(</span>100.0%<span class="o">)</span>
INFO 53887 <span class="nt">---</span> <span class="o">[</span> main] rusframework.report.LoggingReporter : FAILED: 0 <span class="o">(</span>0.0%<span class="o">)</span>
INFO 53887 <span class="nt">---</span> <span class="o">[</span> main] rusframework.report.LoggingReporter : PERFORMANCE: 0 ms
INFO 53887 <span class="nt">---</span> <span class="o">[</span> main] rusframework.report.LoggingReporter :
INFO 53887 <span class="nt">---</span> <span class="o">[</span> main] rusframework.report.LoggingReporter : <span class="nt">------------------------------------------------------------------------</span>
<span class="o">===============================================</span>
Default Suite
Total tests run: 1, Passes: 1, Failures: 0, Skips: 0
<span class="o">===============================================</span>
</code></pre></div></div>
<h2 id="install-citrus-jbang-app">Install Citrus JBang app</h2>
<p>For a more convenient command line usage you can install Citrus as a JBang app.</p>
<p><em>Install Citrus as JBang app</em></p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>jbang trust add https://github.com/citrusframework/citrus/
jbang app <span class="nb">install </span>citrus@citrusframework/citrus
</code></pre></div></div>
<p>Now you can just call <code class="highlighter-rouge">citrus</code> and create and run tests with Citrus JBang.</p>
<p><em>Run my-test.yaml</em></p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>citrus run my-test.yaml
</code></pre></div></div>
<h2 id="run-tests">Run tests</h2>
<p>You can directly run test sources with Citrus JBang.
This includes test sources written in Java (<code class="highlighter-rouge">.java</code>), XML (<code class="highlighter-rouge">.xml</code>), YAML (<code class="highlighter-rouge">.yaml</code>), Groovy (<code class="highlighter-rouge">.groovy</code>) or as a Cucumber Gherkin feature file (<code class="highlighter-rouge">.feature</code>).</p>
<h3 id="java-test-sources">Java test sources</h3>
<p><em>Initialize MyTest.java</em></p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>citrus init MyTest.java
</code></pre></div></div>
<p><em>MyTest.java</em></p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">org.citrusframework.TestCaseRunner</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">org.citrusframework.annotations.CitrusResource</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">static</span> <span class="n">org</span><span class="o">.</span><span class="na">citrusframework</span><span class="o">.</span><span class="na">actions</span><span class="o">.</span><span class="na">CreateVariablesAction</span><span class="o">.</span><span class="na">Builder</span><span class="o">.</span><span class="na">createVariables</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">static</span> <span class="n">org</span><span class="o">.</span><span class="na">citrusframework</span><span class="o">.</span><span class="na">actions</span><span class="o">.</span><span class="na">EchoAction</span><span class="o">.</span><span class="na">Builder</span><span class="o">.</span><span class="na">echo</span><span class="o">;</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">MyTest</span> <span class="kd">implements</span> <span class="n">Runnable</span> <span class="o">{</span>
<span class="nd">@CitrusResource</span>
<span class="n">TestCaseRunner</span> <span class="n">t</span><span class="o">;</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">run</span><span class="o">()</span> <span class="o">{</span>
<span class="n">t</span><span class="o">.</span><span class="na">given</span><span class="o">(</span>
<span class="n">createVariables</span><span class="o">().</span><span class="na">variable</span><span class="o">(</span><span class="s">"message"</span><span class="o">,</span> <span class="s">"Citrus rocks!"</span><span class="o">)</span>
<span class="o">);</span>
<span class="n">t</span><span class="o">.</span><span class="na">then</span><span class="o">(</span>
<span class="n">echo</span><span class="o">().</span><span class="na">message</span><span class="o">(</span><span class="s">"${message}"</span><span class="o">)</span>
<span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<p><em>Run MyTest.java</em></p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>citrus run MyTest.java
</code></pre></div></div>
<h3 id="xml-test-sources">XML test sources</h3>
<p><em>Initialize my-test.xml</em></p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>citrus init my-test.xml
</code></pre></div></div>
<p><em>my-test.xml</em></p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;test</span> <span class="na">name=</span><span class="s">"EchoTest"</span> <span class="na">author=</span><span class="s">"Christoph"</span> <span class="na">status=</span><span class="s">"FINAL"</span> <span class="na">xmlns=</span><span class="s">"http://citrusframework.org/schema/xml/testcase"</span>
<span class="na">xmlns:xsi=</span><span class="s">"http://www.w3.org/2001/XMLSchema-instance"</span>
<span class="na">xsi:schemaLocation=</span><span class="s">"http://citrusframework.org/schema/xml/testcase http://citrusframework.org/schema/xml/testcase/citrus-testcase.xsd"</span><span class="nt">&gt;</span>
<span class="nt">&lt;description&gt;</span>Sample test in XML<span class="nt">&lt;/description&gt;</span>
<span class="nt">&lt;variables&gt;</span>
<span class="nt">&lt;variable</span> <span class="na">name=</span><span class="s">"message"</span> <span class="na">value=</span><span class="s">"Citrus rocks!"</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/variables&gt;</span>
<span class="nt">&lt;actions&gt;</span>
<span class="nt">&lt;echo</span> <span class="na">message=</span><span class="s">"${message}"</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/actions&gt;</span>
<span class="nt">&lt;/test&gt;</span>
</code></pre></div></div>
<p><em>Run my-test.xml</em></p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>citrus run my-test.xml
</code></pre></div></div>
<h3 id="yaml-test-sources">YAML test sources</h3>
<p><em>Initialize my-test.yaml</em></p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>citrus init my-test.yaml
</code></pre></div></div>
<p><em>my-test.yaml</em></p>
<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">name</span><span class="pi">:</span> <span class="s">EchoTest</span>
<span class="na">description</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Sample</span><span class="nv"> </span><span class="s">test</span><span class="nv"> </span><span class="s">in</span><span class="nv"> </span><span class="s">YAML"</span>
<span class="na">variables</span><span class="pi">:</span>
<span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s2">"</span><span class="s">message"</span>
<span class="na">value</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Citrus</span><span class="nv"> </span><span class="s">rocks!"</span>
<span class="na">actions</span><span class="pi">:</span>
<span class="pi">-</span> <span class="na">echo</span><span class="pi">:</span>
<span class="na">message</span><span class="pi">:</span> <span class="s2">"</span><span class="s">${message}"</span>
</code></pre></div></div>
<p><em>Run my-test.yaml</em></p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>citrus run my-test.yaml
</code></pre></div></div>
<h3 id="groovy-test-sources">Groovy test sources</h3>
<p><em>Initialize my-test.groovy</em></p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>citrus init my-test.groovy
</code></pre></div></div>
<p><em>my-test.groovy</em></p>
<div class="language-groovy highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">static</span> <span class="n">org</span><span class="o">.</span><span class="na">citrusframework</span><span class="o">.</span><span class="na">actions</span><span class="o">.</span><span class="na">EchoAction</span><span class="o">.</span><span class="na">Builder</span><span class="o">.</span><span class="na">echo</span>
<span class="n">name</span> <span class="s2">"EchoTest"</span>
<span class="n">description</span> <span class="s2">"Sample test in Groovy"</span>
<span class="n">variables</span> <span class="o">{</span>
<span class="n">message</span><span class="o">=</span><span class="s2">"Citrus rocks!"</span>
<span class="o">}</span>
<span class="n">actions</span> <span class="o">{</span>
<span class="n">$</span><span class="o">(</span><span class="n">echo</span><span class="o">().</span><span class="na">message</span><span class="o">(</span><span class="s1">'${message}'</span><span class="o">))</span>
<span class="o">}</span>
</code></pre></div></div>
<p><em>Run my-test.groovy</em></p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>citrus run my-test.groovy
</code></pre></div></div>
<h3 id="cucumber-feature-sources">Cucumber feature sources</h3>
<p><em>Initialize my-test.feature</em></p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>citrus init my-test.feature
</code></pre></div></div>
<p><em>my-test.feature</em></p>
<div class="language-gherkin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">Feature</span><span class="p">:</span> EchoTest
<span class="kn">Background</span><span class="p">:</span>
<span class="nf">Given </span>variables
<span class="p">|</span> <span class="nv">message</span> <span class="p">|</span> <span class="nv">Citrus</span> <span class="nv">rocks!</span> <span class="p">|</span>
<span class="kn">Scenario</span><span class="p">:</span> Print message
<span class="nf">Then </span>print '${message}'
</code></pre></div></div>
<p><em>Run my-test.feature</em></p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>jbang <span class="nt">--deps</span> org.citrusframework.yaks:yaks-standard:0.20.0 citrus run my-test.feature
</code></pre></div></div>
<p><em>NOTE:</em> Many of the predefined Cucumber steps (e.g. <code class="highlighter-rouge">Then print '&lt;message&gt;'</code>) in Citrus are provided in a separate Citrus child project called <a href="https://github.com/citrusframework/yaks">YAKS</a>.
You need to add additional project dependencies for that steps to be loaded as part of the JBang script.
The <code class="highlighter-rouge">--deps</code> option adds dependencies using Maven artifact coordinates.
You may add the additional modules to the <code class="highlighter-rouge">jbang.properties</code> as described in the next section.</p>
<h2 id="additional-jbang-dependencies">Additional JBang dependencies</h2>
<p>Citrus JBang comes with a set of default dependencies that makes the scripts run as tests.</p>
<p>The default modules that you can use in Citrus JBang are:</p>
<ul>
<li>org.citrusframework:citrus-base</li>
<li>org.citrusframework:citrus-jbang-connector</li>
<li>org.citrusframework:citrus-groovy</li>
<li>org.citrusframework:citrus-xml</li>
<li>org.citrusframework:citrus-yaml</li>
<li>org.citrusframework:citrus-http</li>
<li>org.citrusframework:citrus-validation-json</li>
<li>org.citrusframework:citrus-validation-xml</li>
</ul>
<p>This enables you to run Java, YAML, XML, Groovy tests out of the box.
In case your tests uses an additional feature from the Citrus project you may need to add the module so JBang can load the dependency at startup.</p>
<p>The easiest way to do this is to create a <code class="highlighter-rouge">jbang.properties</code> file that defines the additional dependencies:</p>
<p><em>jbang.properties</em></p>
<div class="language-properties highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Declare required additional dependencies
</span><span class="py">run.deps</span><span class="p">=</span><span class="s">org.citrusframework:citrus-camel:4.5.2,</span><span class="se">\
</span><span class="s">org.citrusframework:citrus-testcontainers:4.5.2,</span><span class="se">\
</span><span class="s">org.citrusframework:citrus-kafka:4.5.2</span>
</code></pre></div></div>
<p>The file above adds the modules <code class="highlighter-rouge">citrus-camel</code>, <code class="highlighter-rouge">citrus-testcontainers</code> and <code class="highlighter-rouge">citrus-kafka</code> so you can use them in your JBang Citrus test source.</p>
<p>The <code class="highlighter-rouge">jbang.properties</code> file may be located right next to the test source file or in your user home directory for global settings.</p>
<p><em>IMPORTANT:</em> In case you want to run Cucumber BDD Gherkin feature files and use the predefined steps included in the <a href="https://github.com/citrusframework/yaks">YAKS</a> project,
you need to add this YAKS runtime dependency accordingly: <code class="highlighter-rouge">org.citrusframework.yaks:yaks-standard:0.20.0</code></p>
<h2 id="run-from-clipboard">Run from clipboard</h2>
<p>You can run tests from your current clipboard.
Just use the file name <code class="highlighter-rouge">clipboard.xxx</code> where the file extension defines the type of the test source (<code class="highlighter-rouge">.java</code>, <code class="highlighter-rouge">.yaml</code>, <code class="highlighter-rouge">.xml</code>, <code class="highlighter-rouge">.groovy</code>, <code class="highlighter-rouge">.feature</code>).</p>
<p><em>Run YAML test from Clipboard</em></p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>citrus run clipboard.yaml
</code></pre></div></div>
<h2 id="list-tests">List tests</h2>
<p>The <code class="highlighter-rouge">ls</code> command lists all running Citrus tests.
These tests may be started</p>
<p><em>List running tests</em></p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>citrus <span class="nb">ls</span>
</code></pre></div></div>
<p><em>Command output</em></p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>PID NAME STATUS AGE
19201 my-test.yaml Running 20s
</code></pre></div></div></content><author><name></name></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://0.0.0.0:4000/img/icons/jbang.png" /></entry><entry><title type="html">Quarkus sample</title><link href="http://0.0.0.0:4000/samples/quarkus/" rel="alternate" type="text/html" title="Quarkus sample" /><published>2023-11-03T00:00:00+01:00</published><updated>2023-11-03T00:00:00+01:00</updated><id>http://0.0.0.0:4000/samples/sample-quarkus</id><content type="html" xml:base="http://0.0.0.0:4000/samples/quarkus/"><p>This project uses Quarkus to implement a sample event-driven application and shows how to verify the event processing with an automated integration test written in <a href="https://citrusframework.org">Citrus</a>.
The Quarkus support in Citrus is described in more detail in <a href="https://citrusframework.org/citrus/reference/html#runtime-quarkus">reference guide</a></p>
<h2 id="objectives">Objectives</h2>
<p>The project uses the Quarkus test framework to set up a dev services environment with JUnit Jupiter where the application is running on the local machine.
The Quarkus dev services capabilities will automatically start Testcontainers during the test in order to simulate the surrounding infrastructure
(e.g. PostgreSQL database and the Kafka message broker).</p>
<p>If you want to learn more about Quarkus, please visit its website: <a href="https://quarkus.io/">https://quarkus.io/</a>.</p>
<h2 id="quarkus-sample-application">Quarkus sample application</h2>
<p>The Quarkus sample demo application is a food market event-driven application that listens for incoming events of type <code class="highlighter-rouge">booking</code> and <code class="highlighter-rouge">supply</code>.</p>
<p><img src="/img/assets/sample-quarkus/food-market-app-demo.png" alt="Food Market App" /></p>
<p>Users are able to add booking events. Each of them references a product and gives an amount as well as an accepted price in a simple Json object structure.</p>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w"> </span><span class="s2">"client"</span><span class="p">:</span><span class="w"> </span><span class="s2">"citrus-test"</span><span class="p">,</span><span class="w"> </span><span class="s2">"product"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Pineapple"</span><span class="p">,</span><span class="w"> </span><span class="s2">"amount"</span><span class="p">:</span><span class="w"> </span><span class="mi">100</span><span class="p">,</span><span class="w"> </span><span class="s2">"price"</span><span class="p">:</span><span class="w"> </span><span class="mf">0.99</span><span class="w"> </span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<p>At the same time suppliers may add their individual supply events that again reference a product with an amount and a selling price.</p>
<p>The Quarkus application consumes both event types and as soon as bookings and supplies do match in all criteria the food market application will produce booking-completed and shipping events as a result.</p>
<p>All events are produced and consumed with Kafka event streams.
The domain model objects with their individual status are stored in a PostgreSQL database.</p>
<h2 id="adding-citrus-to-the-project">Adding Citrus to the project</h2>
<p>Looking at the Maven <code class="highlighter-rouge">pom.xml</code> you will see that Citrus is added as a test scoped dependency.
The most convenient way to add Citrus to your project is to import the <code class="highlighter-rouge">citrus-bom</code>.</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;dependencyManagement&gt;</span>
<span class="nt">&lt;dependencies&gt;</span>
<span class="nt">&lt;dependency&gt;</span>
<span class="nt">&lt;groupId&gt;</span>org.citrusframework<span class="nt">&lt;/groupId&gt;</span>
<span class="nt">&lt;artifactId&gt;</span>citrus-bom<span class="nt">&lt;/artifactId&gt;</span>
<span class="nt">&lt;version&gt;</span>4.5.2<span class="nt">&lt;/version&gt;</span>
<span class="nt">&lt;type&gt;</span>pom<span class="nt">&lt;/type&gt;</span>
<span class="nt">&lt;scope&gt;</span>import<span class="nt">&lt;/scope&gt;</span>
<span class="nt">&lt;/dependency&gt;</span>
<span class="nt">&lt;/dependencies&gt;</span>
<span class="nt">&lt;/dependencyManagement&gt;</span>
</code></pre></div></div>
<p>Citrus is very modular. This means you can choose from a wide range of modules that add specific testing capabilities to the project (e.g. citrus-kafka, citrus-http, citrus-mail, …).
In this sample project we include the following modules as test scoped dependencies:</p>
<ul>
<li>citrus-quarkus</li>
<li>citrus-kafka</li>
<li>citrus-http</li>
<li>citrus-sql</li>
<li>citrus-selenium</li>
<li>citrus-validation-json</li>
<li>citrus-validation-text</li>
</ul>
<p>The <code class="highlighter-rouge">citrus-quarkus</code> module provides the QuarkusTest resource implementation that enables Citrus on a Quarkus test.</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;dependency&gt;</span>
<span class="nt">&lt;groupId&gt;</span>org.citrusframework<span class="nt">&lt;/groupId&gt;</span>
<span class="nt">&lt;artifactId&gt;</span>citrus-quarkus<span class="nt">&lt;/artifactId&gt;</span>
<span class="nt">&lt;/dependency&gt;</span>
</code></pre></div></div>
<p>The other modules add very specific Citrus capabilities such as validation of a Json message payload.</p>
<p>This completes the dependency setup.
Now we can move on to writing an automated integration test that verifies the Quarkus application.</p>
<h2 id="enable-citrus-with-quarkustest">Enable Citrus with @QuarkusTest</h2>
<p>The test uses an arbitrary <code class="highlighter-rouge">@QuarkusTest</code> annotation with JUnit Jupiter.
This means that Quarkus takes care of starting the application under test.
It also starts some Testcontainers for the PostgreSQL database and the Kafka message broker.</p>
<p>You can enable the Citrus capabilities on the test by adding the <code class="highlighter-rouge">@CitrusSupport</code> annotation to the test class.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@QuarkusTest</span>
<span class="nd">@CitrusSupport</span>
<span class="kd">class</span> <span class="nc">FoodMarketApplicationTest</span> <span class="o">{</span>
<span class="nd">@CitrusResource</span>
<span class="n">TestCaseRunner</span> <span class="n">t</span><span class="o">;</span>
<span class="nd">@Inject</span>
<span class="n">ObjectMapper</span> <span class="n">mapper</span><span class="o">;</span>
<span class="nd">@Test</span>
<span class="kt">void</span> <span class="nf">shouldProcessEvents</span><span class="o">()</span> <span class="o">{</span>
<span class="n">createBooking</span><span class="o">();</span>
<span class="n">createSupply</span><span class="o">();</span>
<span class="n">verifyBookingCompletedEvent</span><span class="o">();</span>
<span class="n">verifyShippingEvent</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<p>The Citrus enabled test is able to inject additional resources such as the <code class="highlighter-rouge">TestCaseRunner</code>.
This runner is the entrance to all Citrus related test actions like send/receive messages or querying and verifying entities in the database.</p>
<p>The test will perform four main actions:</p>
<ul>
<li>Create a booking event</li>
<li>Create a matching supply event</li>
<li>Verify the booking completed event</li>
<li>Verify the shipping event</li>
</ul>
<p>In first version of the test all events will be sent/received via the Kafka message broker.</p>
<h2 id="stage-1-prototyping-the-test">Stage #1: Prototyping the test</h2>
<p>Citrus is able to send and receive messages via Kafka quite easily.
You can use a dynamic endpoint URL (e.g. <code class="highlighter-rouge">kafka:my-topic-name</code>) to exchange data.
The message content (header and body) is given with simple inline Json Strings in this first prototype.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@QuarkusTest</span>
<span class="nd">@CitrusSupport</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">FoodMarketDemoTest</span> <span class="o">{</span>
<span class="nd">@CitrusResource</span>
<span class="n">TestCaseRunner</span> <span class="n">t</span><span class="o">;</span>
<span class="nd">@Test</span>
<span class="kt">void</span> <span class="nf">shouldMatchBookingAndSupply</span><span class="o">()</span> <span class="o">{</span>
<span class="n">createBooking</span><span class="o">();</span>
<span class="n">createSupply</span><span class="o">();</span>
<span class="n">verifyBookingCompletedEvent</span><span class="o">();</span>
<span class="n">verifyShippingEvent</span><span class="o">();</span>
<span class="o">}</span>
<span class="kd">private</span> <span class="kt">void</span> <span class="nf">createBooking</span><span class="o">()</span> <span class="o">{</span>
<span class="n">t</span><span class="o">.</span><span class="na">when</span><span class="o">(</span><span class="n">send</span><span class="o">()</span>
<span class="o">.</span><span class="na">endpoint</span><span class="o">(</span><span class="s">"kafka:bookings"</span><span class="o">)</span>
<span class="o">.</span><span class="na">message</span><span class="o">()</span>
<span class="o">.</span><span class="na">body</span><span class="o">(</span><span class="s">"""
{
"</span><span class="n">client</span><span class="s">": "</span><span class="n">citrus</span><span class="s">",
"</span><span class="n">product</span><span class="s">": {
"</span><span class="n">name</span><span class="s">": "</span><span class="n">Kiwi</span><span class="s">"
},
"</span><span class="n">amount</span><span class="s">": 10,
"</span><span class="n">price</span><span class="s">": 0.99,
"</span><span class="n">shippingAddress</span><span class="s">": "</span><span class="mo">001</span><span class="o">,</span> <span class="n">Foo</span> <span class="n">Blvd</span><span class="o">.</span><span class="s">"
}
"""</span><span class="o">)</span>
<span class="o">);</span>
<span class="o">}</span>
<span class="c1">//...</span>
<span class="o">}</span>
</code></pre></div></div>
<p>The injected Citrus <code class="highlighter-rouge">TestCaseRunner</code> <code class="highlighter-rouge">t</code> is able to use Gherkin Given-When-Then syntax and references the KafkaEndpoint <code class="highlighter-rouge">kafka:bookings</code> in the send operation.
The message body is a simple Json String that represents the booking.</p>
<p>The rest of the story is quite easy.
In the same way we can also send a <code class="highlighter-rouge">supply</code> event and then receive <code class="highlighter-rouge">completed</code> and <code class="highlighter-rouge">shipping</code> events in the test.</p>
<p>When receiving the <code class="highlighter-rouge">completed</code> and <code class="highlighter-rouge">shipping</code> events the test is able to use the Citrus Json validation power coming with the <code class="highlighter-rouge">citrus-validation-json</code> module.
Citrus will compare the received Json object with an expected template and make sure that all fields and properties do match as expected.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">FoodMarketApplicationTest</span> <span class="o">{</span>
<span class="c1">// ...</span>
<span class="kd">private</span> <span class="kt">void</span> <span class="nf">verifyBookingCompletedEvent</span><span class="o">()</span> <span class="o">{</span>
<span class="n">t</span><span class="o">.</span><span class="na">then</span><span class="o">(</span><span class="n">receive</span><span class="o">()</span>
<span class="o">.</span><span class="na">endpoint</span><span class="o">(</span><span class="s">"kafka:completed?timeout=10000&amp;consumerGroup=citrus-booking"</span><span class="o">)</span>
<span class="o">.</span><span class="na">message</span><span class="o">()</span>
<span class="o">.</span><span class="na">body</span><span class="o">(</span><span class="s">"""
{
"</span><span class="n">client</span><span class="s">": "</span><span class="n">citrus</span><span class="s">",
"</span><span class="n">product</span><span class="s">": "</span><span class="n">Kiwi</span><span class="s">",
"</span><span class="n">amount</span><span class="s">": 10,
"</span><span class="n">status</span><span class="s">": "</span><span class="n">COMPLETED</span><span class="s">"
}
"""</span><span class="o">)</span>
<span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<p>The Citrus Json validation will now compare the received event with the expected Json object and fail the test when there is a mismatch.</p>
<p><em>Citrus Json validation</em></p>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w"> </span><span class="s2">"client"</span><span class="p">:</span><span class="w"> </span><span class="s2">"citrus"</span><span class="p">,</span><span class="w"> </span><span class="s2">"product"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Kiwi"</span><span class="p">,</span><span class="w"> </span><span class="s2">"amount"</span><span class="p">:</span><span class="w"> </span><span class="mi">10</span><span class="p">,</span><span class="w"> </span><span class="s2">"status"</span><span class="p">:</span><span class="w"> </span><span class="s2">"COMPLETED"</span><span class="w"> </span><span class="p">}</span><span class="w">
</span><span class="err">//</span><span class="w"> </span><span class="err">compared</span><span class="w"> </span><span class="err">to</span><span class="w">
</span><span class="p">{</span><span class="w"> </span><span class="s2">"client"</span><span class="p">:</span><span class="w"> </span><span class="s2">"citrus"</span><span class="p">,</span><span class="w"> </span><span class="s2">"product"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Kiwi"</span><span class="p">,</span><span class="w"> </span><span class="s2">"amount"</span><span class="p">:</span><span class="w"> </span><span class="mi">10</span><span class="p">,</span><span class="w"> </span><span class="s2">"status"</span><span class="p">:</span><span class="w"> </span><span class="s2">"COMPLETED"</span><span class="w"> </span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<p>The Json validation is very powerful.
You can ignore properties (expected value set to <code class="highlighter-rouge">@ignore@</code>), use validation matchers, functions and test variables.
A mismatch in the order of elements or some difference in the formatting of the Json document is not failing the test.</p>
<p>In case there is a mismatch you will be provided with an error and the test fails accordingly.</p>
<h2 id="running-the-citrus-tests">Running the Citrus tests</h2>
<p>The Quarkus test framework uses JUnit Jupiter as a test driver.
This means you can run the tests just like any other JUnit test (e.g. from your Java IDE, with Maven).</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>./mvnw <span class="nb">test</span>
</code></pre></div></div>
<p>The Citrus test capabilities are added on top of <code class="highlighter-rouge">@QuarkusTest</code> with the <code class="highlighter-rouge">@CitrusSupport</code> annotation.
So you will not need any other configuration to empower the tests with Citrus.</p>
<h2 id="stage-2-use-endpoint-builders-and-domain-model-objects">Stage #2: Use endpoint builders and domain model objects</h2>
<p>Using the dynamic endpoint <code class="highlighter-rouge">kafka:my-topic-name</code> may be a good and easy start for prototyping.
When it comes to writing more tests in your project you may want to leverage a central Kafka endpoint configuration and reuse it in multiple tests.</p>
<p>You can add a <code class="highlighter-rouge">@CitrusConfiguration</code> annotation that loads endpoints from one to many configuration classes.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@QuarkusTest</span>
<span class="nd">@CitrusSupport</span>
<span class="nd">@CitrusConfiguration</span><span class="o">(</span><span class="n">classes</span> <span class="o">=</span> <span class="o">{</span> <span class="n">CitrusEndpointConfig</span><span class="o">.</span><span class="na">class</span> <span class="o">})</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">FoodMarketDemoTest</span> <span class="o">{</span>
<span class="nd">@CitrusResource</span>
<span class="n">TestCaseRunner</span> <span class="n">t</span><span class="o">;</span>
<span class="nd">@CitrusEndpoint</span>
<span class="n">KafkaEndpoint</span> <span class="n">supplies</span><span class="o">;</span>
<span class="nd">@CitrusEndpoint</span>
<span class="n">KafkaEndpoint</span> <span class="n">bookings</span><span class="o">;</span>
<span class="nd">@CitrusEndpoint</span>
<span class="n">KafkaEndpoint</span> <span class="n">completed</span><span class="o">;</span>
<span class="nd">@CitrusEndpoint</span>
<span class="n">KafkaEndpoint</span> <span class="n">shipping</span><span class="o">;</span>
<span class="c1">// code the tests</span>
<span class="o">}</span>
</code></pre></div></div>
<p>In the loaded <code class="highlighter-rouge">CitrusEndpointConfig</code> class the Kafka endpoint instances get configured for all tests that load the configuration.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">CitrusEndpointConfig</span> <span class="o">{</span>
<span class="nd">@BindToRegistry</span>
<span class="kd">public</span> <span class="n">KafkaEndpoint</span> <span class="nf">bookings</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="nf">kafka</span><span class="o">()</span>
<span class="o">.</span><span class="na">asynchronous</span><span class="o">()</span>
<span class="o">.</span><span class="na">topic</span><span class="o">(</span><span class="s">"bookings"</span><span class="o">)</span>
<span class="o">.</span><span class="na">build</span><span class="o">();</span>
<span class="o">}</span>
<span class="nd">@BindToRegistry</span>
<span class="kd">public</span> <span class="n">KafkaEndpoint</span> <span class="nf">supplies</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="nf">kafka</span><span class="o">()</span>
<span class="o">.</span><span class="na">asynchronous</span><span class="o">()</span>
<span class="o">.</span><span class="na">topic</span><span class="o">(</span><span class="s">"supplies"</span><span class="o">)</span>
<span class="o">.</span><span class="na">build</span><span class="o">();</span>
<span class="o">}</span>
<span class="nd">@BindToRegistry</span>
<span class="kd">public</span> <span class="n">KafkaEndpoint</span> <span class="nf">shipping</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="nf">kafka</span><span class="o">()</span>
<span class="o">.</span><span class="na">asynchronous</span><span class="o">()</span>
<span class="o">.</span><span class="na">topic</span><span class="o">(</span><span class="s">"shipping"</span><span class="o">)</span>
<span class="o">.</span><span class="na">consumerGroup</span><span class="o">(</span><span class="s">"citrus-shipping"</span><span class="o">)</span>
<span class="o">.</span><span class="na">timeout</span><span class="o">(</span><span class="mi">10000L</span><span class="o">)</span>
<span class="o">.</span><span class="na">build</span><span class="o">();</span>
<span class="o">}</span>
<span class="nd">@BindToRegistry</span>
<span class="kd">public</span> <span class="n">KafkaEndpoint</span> <span class="nf">completed</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="nf">kafka</span><span class="o">()</span>
<span class="o">.</span><span class="na">asynchronous</span><span class="o">()</span>
<span class="o">.</span><span class="na">topic</span><span class="o">(</span><span class="s">"completed"</span><span class="o">)</span>
<span class="o">.</span><span class="na">consumerGroup</span><span class="o">(</span><span class="s">"citrus-completed"</span><span class="o">)</span>
<span class="o">.</span><span class="na">timeout</span><span class="o">(</span><span class="mi">10000L</span><span class="o">)</span>
<span class="o">.</span><span class="na">build</span><span class="o">();</span>
<span class="o">}</span>
<span class="c1">// more endpoints</span>
<span class="o">}</span>
</code></pre></div></div>
<p>The configuration class uses the KafkaEndpoint builder and binds the components to the Citrus registry.
With that configuration you can inject the endpoint instances in your test with the <code class="highlighter-rouge">@CitrusEndpoint</code> annotation.</p>
<p>Now you can reference the endpoint in Citrus send/receive test actions.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Product</span> <span class="n">product</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Product</span><span class="o">(</span><span class="s">"Kiwi"</span><span class="o">);</span>
<span class="n">Booking</span> <span class="n">booking</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Booking</span><span class="o">(</span><span class="s">"citrus"</span><span class="o">,</span> <span class="n">product</span><span class="o">,</span> <span class="mi">10</span><span class="o">,</span> <span class="mf">0.99</span><span class="n">D</span><span class="o">,</span> <span class="n">TestHelper</span><span class="o">.</span><span class="na">createShippingAddress</span><span class="o">().</span><span class="na">getFullAddress</span><span class="o">());</span>
<span class="kd">private</span> <span class="kt">void</span> <span class="nf">createBooking</span><span class="o">(</span><span class="n">Booking</span> <span class="n">booking</span><span class="o">)</span> <span class="o">{</span>
<span class="n">t</span><span class="o">.</span><span class="na">when</span><span class="o">(</span><span class="n">send</span><span class="o">()</span>
<span class="o">.</span><span class="na">endpoint</span><span class="o">(</span><span class="n">bookings</span><span class="o">)</span>
<span class="o">.</span><span class="na">message</span><span class="o">()</span>
<span class="o">.</span><span class="na">body</span><span class="o">(</span><span class="n">marshal</span><span class="o">(</span><span class="n">booking</span><span class="o">))</span>
<span class="o">);</span>
<span class="o">}</span>
</code></pre></div></div>
<p>Another improvement for the test is to use the domain model object <code class="highlighter-rouge">Booking</code> as a message payload instead of using the inline Json String.</p>
<h2 id="stage-3-add-mail-verification">Stage #3: Add mail verification</h2>
<p>So far the test has been using Kafka endpoints exclusively.
Citrus provides a huge set of components to connect to different messaging transports and technologies.</p>
<p>As a next step the test verifies a mail message that is sent by the Quarkus application when a booking has been completed.</p>
<p>First of all the configuration adds a Citrus mail server.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@BindToRegistry</span>
<span class="kd">public</span> <span class="n">MailServer</span> <span class="nf">mailServer</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="nf">mail</span><span class="o">().</span><span class="na">server</span><span class="o">()</span>
<span class="o">.</span><span class="na">port</span><span class="o">(</span><span class="mi">2222</span><span class="o">)</span>
<span class="o">.</span><span class="na">knownUsers</span><span class="o">(</span><span class="n">Collections</span><span class="o">.</span><span class="na">singletonList</span><span class="o">(</span><span class="s">"foodmarket@quarkus.io:foodmarket:secr3t"</span><span class="o">))</span>
<span class="o">.</span><span class="na">autoAccept</span><span class="o">(</span><span class="kc">true</span><span class="o">)</span>
<span class="o">.</span><span class="na">autoStart</span><span class="o">(</span><span class="kc">true</span><span class="o">)</span>
<span class="o">.</span><span class="na">build</span><span class="o">();</span>
<span class="o">}</span>
</code></pre></div></div>
<p>The mail server accepts incoming mail requests on port <code class="highlighter-rouge">2222</code> and adds some known users.
The Quarkus application then uses the connection credentials in the <code class="highlighter-rouge">application.properties</code>.</p>
<div class="language-properties highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="py">quarkus.mailer.mock</span><span class="p">=</span><span class="s">false</span>
<span class="py">quarkus.mailer.own-host-name</span><span class="p">=</span><span class="s">localhost</span>
<span class="py">quarkus.mailer.from</span><span class="p">=</span><span class="s">foodmarket@quarkus.io</span>
<span class="py">quarkus.mailer.host</span><span class="p">=</span><span class="s">localhost</span>
<span class="py">quarkus.mailer.port</span><span class="p">=</span><span class="s">2222</span>
<span class="py">quarkus.mailer.username</span><span class="p">=</span><span class="s">foodmarket</span>
<span class="py">quarkus.mailer.password</span><span class="p">=</span><span class="s">secr3t</span>
<span class="py">quarkus.mailer.start-tls</span><span class="p">=</span><span class="s">OPTIONAL</span>
</code></pre></div></div>
<p>The test is able to reference this mail server to verify the mail sent by Quarkus.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">private</span> <span class="kt">void</span> <span class="nf">verifyBookingCompletedMail</span><span class="o">(</span><span class="n">Booking</span> <span class="n">booking</span><span class="o">)</span> <span class="o">{</span>
<span class="n">t</span><span class="o">.</span><span class="na">then</span><span class="o">(</span><span class="n">receive</span><span class="o">()</span>
<span class="o">.</span><span class="na">endpoint</span><span class="o">(</span><span class="n">mailServer</span><span class="o">)</span>
<span class="o">.</span><span class="na">message</span><span class="o">(</span><span class="n">MailMessage</span><span class="o">.</span><span class="na">request</span><span class="o">()</span>
<span class="o">.</span><span class="na">from</span><span class="o">(</span><span class="s">"foodmarket@quarkus.io"</span><span class="o">)</span>
<span class="o">.</span><span class="na">to</span><span class="o">(</span><span class="s">"%s@quarkus.io"</span><span class="o">.</span><span class="na">formatted</span><span class="o">(</span><span class="n">booking</span><span class="o">.</span><span class="na">getClient</span><span class="o">()))</span>
<span class="o">.</span><span class="na">subject</span><span class="o">(</span><span class="s">"Booking completed!"</span><span class="o">)</span>
<span class="o">.</span><span class="na">body</span><span class="o">(</span><span class="s">"Hey %s, your booking %s has been completed."</span>
<span class="o">.</span><span class="na">formatted</span><span class="o">(</span><span class="n">booking</span><span class="o">.</span><span class="na">getClient</span><span class="o">(),</span> <span class="n">booking</span><span class="o">.</span><span class="na">getProduct</span><span class="o">().</span><span class="na">getName</span><span class="o">()),</span> <span class="s">"text/plain"</span><span class="o">)));</span>
<span class="n">t</span><span class="o">.</span><span class="na">then</span><span class="o">(</span><span class="n">send</span><span class="o">()</span>
<span class="o">.</span><span class="na">endpoint</span><span class="o">(</span><span class="n">mailServer</span><span class="o">)</span>
<span class="o">.</span><span class="na">message</span><span class="o">(</span><span class="n">MailMessage</span><span class="o">.</span><span class="na">response</span><span class="o">(</span><span class="mi">250</span><span class="o">)));</span>
<span class="o">}</span>
</code></pre></div></div>
<p>The mail verification includes the validation of all mail related properties (e.g. from, to, subject, body) and the simulation of the mail server response (250 OK).
This is a good point to simulate a mail server error in order to verify the resilience and the error handling on the Quarkus application.</p>
<h2 id="stage-4-use-testbehaviors">Stage #4: Use TestBehaviors</h2>
<p>Citrus has the concept of TestBehaviors to reuse a set of test actions in multiple tests.
The mail verification steps may be added into a behavior so many tests can make use of it.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">VerifyBookingCompletedMail</span> <span class="kd">implements</span> <span class="n">TestBehavior</span> <span class="o">{</span>
<span class="kd">private</span> <span class="kd">final</span> <span class="n">Booking</span> <span class="n">booking</span><span class="o">;</span>
<span class="kd">private</span> <span class="kd">final</span> <span class="n">MailServer</span> <span class="n">mailServer</span><span class="o">;</span>
<span class="kd">public</span> <span class="nf">VerifyBookingCompletedMail</span><span class="o">(</span><span class="n">Booking</span> <span class="n">booking</span><span class="o">,</span> <span class="n">MailServer</span> <span class="n">mailServer</span><span class="o">)</span> <span class="o">{</span>
<span class="k">this</span><span class="o">.</span><span class="na">booking</span> <span class="o">=</span> <span class="n">booking</span><span class="o">;</span>
<span class="k">this</span><span class="o">.</span><span class="na">mailServer</span> <span class="o">=</span> <span class="n">mailServer</span><span class="o">;</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">apply</span><span class="o">(</span><span class="n">TestActionRunner</span> <span class="n">t</span><span class="o">)</span> <span class="o">{</span>
<span class="n">t</span><span class="o">.</span><span class="na">run</span><span class="o">(</span><span class="n">receive</span><span class="o">()</span>
<span class="o">.</span><span class="na">endpoint</span><span class="o">(</span><span class="n">mailServer</span><span class="o">)</span>
<span class="o">.</span><span class="na">message</span><span class="o">(</span><span class="n">MailMessage</span><span class="o">.</span><span class="na">request</span><span class="o">()</span>
<span class="o">.</span><span class="na">from</span><span class="o">(</span><span class="s">"foodmarket@quarkus.io"</span><span class="o">)</span>
<span class="o">.</span><span class="na">to</span><span class="o">(</span><span class="s">"%s@quarkus.io"</span><span class="o">.</span><span class="na">formatted</span><span class="o">(</span><span class="n">booking</span><span class="o">.</span><span class="na">getClient</span><span class="o">()))</span>
<span class="o">.</span><span class="na">subject</span><span class="o">(</span><span class="s">"Booking completed!"</span><span class="o">)</span>
<span class="o">.</span><span class="na">body</span><span class="o">(</span><span class="s">"Hey %s, your booking %s has been completed."</span>
<span class="o">.</span><span class="na">formatted</span><span class="o">(</span><span class="n">booking</span><span class="o">.</span><span class="na">getClient</span><span class="o">(),</span> <span class="n">booking</span><span class="o">.</span><span class="na">getProduct</span><span class="o">().</span><span class="na">getName</span><span class="o">()),</span> <span class="s">"text/plain"</span><span class="o">))</span>
<span class="o">);</span>
<span class="n">t</span><span class="o">.</span><span class="na">run</span><span class="o">(</span><span class="n">send</span><span class="o">()</span>
<span class="o">.</span><span class="na">endpoint</span><span class="o">(</span><span class="n">mailServer</span><span class="o">)</span>
<span class="o">.</span><span class="na">message</span><span class="o">(</span><span class="n">MailMessage</span><span class="o">.</span><span class="na">response</span><span class="o">())</span>
<span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<p>The test is able to apply the behavior quite easily.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">private</span> <span class="kt">void</span> <span class="nf">verifyBookingCompletedMail</span><span class="o">(</span><span class="n">Booking</span> <span class="n">booking</span><span class="o">)</span> <span class="o">{</span>
<span class="n">t</span><span class="o">.</span><span class="na">then</span><span class="o">(</span><span class="n">t</span><span class="o">.</span><span class="na">applyBehavior</span><span class="o">(</span><span class="k">new</span> <span class="n">VerifyBookingCompletedMail</span><span class="o">(</span><span class="n">booking</span><span class="o">,</span> <span class="n">mailServer</span><span class="o">)));</span>
<span class="o">}</span>
</code></pre></div></div>
<h2 id="stage-5-use-the-http-rest-api">Stage #5: Use the Http REST API</h2>
<p>The Quarkus application under test also provides a Http REST API to manage bookings and supplies.</p>
<p>The Citrus test is able to call the REST API with a Http client.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@BindToRegistry</span>
<span class="kd">public</span> <span class="n">HttpClient</span> <span class="nf">foodMarketApiClient</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="nf">http</span><span class="o">().</span><span class="na">client</span><span class="o">()</span>
<span class="o">.</span><span class="na">requestUrl</span><span class="o">(</span><span class="s">"http://localhost:8081"</span><span class="o">)</span>
<span class="o">.</span><span class="na">build</span><span class="o">();</span>
<span class="o">}</span>
</code></pre></div></div>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">private</span> <span class="kt">void</span> <span class="nf">createBooking</span><span class="o">(</span><span class="n">Booking</span> <span class="n">booking</span><span class="o">)</span> <span class="o">{</span>
<span class="n">t</span><span class="o">.</span><span class="na">when</span><span class="o">(</span><span class="n">http</span><span class="o">()</span>
<span class="o">.</span><span class="na">client</span><span class="o">(</span><span class="n">foodMarketApiClient</span><span class="o">)</span>
<span class="o">.</span><span class="na">send</span><span class="o">()</span>
<span class="o">.</span><span class="na">post</span><span class="o">(</span><span class="s">"/api/bookings"</span><span class="o">)</span>
<span class="o">.</span><span class="na">message</span><span class="o">()</span>
<span class="o">.</span><span class="na">contentType</span><span class="o">(</span><span class="n">MediaType</span><span class="o">.</span><span class="na">APPLICATION_JSON_VALUE</span><span class="o">)</span>
<span class="o">.</span><span class="na">body</span><span class="o">(</span><span class="n">marshal</span><span class="o">(</span><span class="n">booking</span><span class="o">))</span>
<span class="o">);</span>
<span class="n">t</span><span class="o">.</span><span class="na">then</span><span class="o">(</span><span class="n">http</span><span class="o">()</span>
<span class="o">.</span><span class="na">client</span><span class="o">(</span><span class="n">foodMarketApiClient</span><span class="o">)</span>
<span class="o">.</span><span class="na">receive</span><span class="o">()</span>
<span class="o">.</span><span class="na">response</span><span class="o">(</span><span class="n">HttpStatus</span><span class="o">.</span><span class="na">CREATED</span><span class="o">)</span>
<span class="o">.</span><span class="na">message</span><span class="o">()</span>
<span class="o">.</span><span class="na">extract</span><span class="o">(</span><span class="n">json</span><span class="o">().</span><span class="na">expression</span><span class="o">(</span><span class="s">"$.id"</span><span class="o">,</span> <span class="s">"bookingId"</span><span class="o">))</span>
<span class="o">);</span>
<span class="o">}</span>
</code></pre></div></div>
<p>The test now sends a Http POST request to create the booking.
The client is able to verify the Http response <code class="highlighter-rouge">201 CREATED</code> and also save the generated booking id for later reference in the test.</p>
<h1 id="stage-6-verify-entities-in-the-database">Stage #6: Verify entities in the database</h1>
<p>The test may also verify the entities saved to the PostgreSQL database.
The <code class="highlighter-rouge">@QuarkusTest</code> dev services is able to inject the dataSource that connects to the PostgreSQL database Testcontainers that is startes as part of the test.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@Inject</span>
<span class="n">DataSource</span> <span class="n">dataSource</span><span class="o">;</span>
<span class="kd">private</span> <span class="kt">void</span> <span class="nf">verifyBookingStatus</span><span class="o">(</span><span class="n">Booking</span><span class="o">.</span><span class="na">Status</span> <span class="n">status</span><span class="o">)</span> <span class="o">{</span>
<span class="n">t</span><span class="o">.</span><span class="na">then</span><span class="o">(</span><span class="n">sql</span><span class="o">()</span>
<span class="o">.</span><span class="na">dataSource</span><span class="o">(</span><span class="n">dataSource</span><span class="o">)</span>
<span class="o">.</span><span class="na">query</span><span class="o">()</span>
<span class="o">.</span><span class="na">statement</span><span class="o">(</span><span class="s">"select status from booking where booking.id=${bookingId}"</span><span class="o">)</span>
<span class="o">.</span><span class="na">validate</span><span class="o">(</span><span class="s">"status"</span><span class="o">,</span> <span class="n">status</span><span class="o">.</span><span class="na">name</span><span class="o">())</span>
<span class="o">);</span>
<span class="o">}</span>
</code></pre></div></div>
<p>The SQL verification uses the extracted <code class="highlighter-rouge">bookingId</code> test variable to identify the entity in the database.
The returned result set gets verified with the expected column values (e.g. <code class="highlighter-rouge">status=COMPLETED</code>)</p>
<h2 id="stage-7-use-openapi-specification">Stage #7: Use OpenAPI specification</h2>
<p>The Quarkus application also exposes its OpenAPI specification for the REST API.
The Citrus test is able to leverage this specification when sending/receiving Http messages.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">private</span> <span class="kd">final</span> <span class="n">OpenApiSpecification</span> <span class="n">foodMarketSpec</span> <span class="o">=</span>
<span class="n">OpenApiSpecification</span><span class="o">.</span><span class="na">from</span><span class="o">(</span><span class="s">"http://localhost:8081/q/openapi"</span><span class="o">);</span>
<span class="kd">private</span> <span class="kt">void</span> <span class="nf">createBooking</span><span class="o">(</span><span class="n">Booking</span> <span class="n">booking</span><span class="o">)</span> <span class="o">{</span>
<span class="n">t</span><span class="o">.</span><span class="na">when</span><span class="o">(</span><span class="n">openapi</span><span class="o">()</span>
<span class="o">.</span><span class="na">specification</span><span class="o">(</span><span class="n">foodMarketSpec</span><span class="o">)</span>
<span class="o">.</span><span class="na">client</span><span class="o">(</span><span class="n">foodMarketApiClient</span><span class="o">)</span>
<span class="o">.</span><span class="na">send</span><span class="o">(</span><span class="s">"addBooking"</span><span class="o">)</span>
<span class="o">.</span><span class="na">message</span><span class="o">()</span>
<span class="o">.</span><span class="na">body</span><span class="o">(</span><span class="n">marshal</span><span class="o">(</span><span class="n">booking</span><span class="o">))</span>
<span class="o">);</span>
<span class="n">t</span><span class="o">.</span><span class="na">then</span><span class="o">(</span><span class="n">openapi</span><span class="o">()</span>
<span class="o">.</span><span class="na">specification</span><span class="o">(</span><span class="n">foodMarketSpec</span><span class="o">)</span>
<span class="o">.</span><span class="na">client</span><span class="o">(</span><span class="n">foodMarketApiClient</span><span class="o">)</span>
<span class="o">.</span><span class="na">receive</span><span class="o">(</span><span class="s">"addBooking"</span><span class="o">,</span> <span class="n">HttpStatus</span><span class="o">.</span><span class="na">CREATED</span><span class="o">)</span>
<span class="o">.</span><span class="na">message</span><span class="o">()</span>
<span class="o">.</span><span class="na">extract</span><span class="o">(</span><span class="n">json</span><span class="o">().</span><span class="na">expression</span><span class="o">(</span><span class="s">"$.id"</span><span class="o">,</span> <span class="s">"bookingId"</span><span class="o">))</span>
<span class="o">);</span>
<span class="o">}</span>
</code></pre></div></div>
<p>The test loads the OpenAPI specification from the Quarkus application with the URL <code class="highlighter-rouge">http://localhost:8081/q/openapi</code>.
The specification then is used with the Http send test action.</p>
<p>The action references an operation with the id <code class="highlighter-rouge">addBooking</code>.</p>
<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">---</span>
<span class="na">openapi</span><span class="pi">:</span> <span class="s">3.0.3</span>
<span class="na">info</span><span class="pi">:</span>
<span class="na">title</span><span class="pi">:</span> <span class="s">citrus-demo-quarkus API</span>
<span class="na">version</span><span class="pi">:</span> <span class="s">1.0.0</span>
<span class="na">servers</span><span class="pi">:</span>
<span class="pi">-</span> <span class="na">url</span><span class="pi">:</span> <span class="s">http://localhost:8080</span>
<span class="na">description</span><span class="pi">:</span> <span class="s">Auto generated value</span>
<span class="pi">-</span> <span class="na">url</span><span class="pi">:</span> <span class="s">http://0.0.0.0:8080</span>
<span class="na">description</span><span class="pi">:</span> <span class="s">Auto generated value</span>
<span class="na">paths</span><span class="pi">:</span>
<span class="s">/api/bookings</span><span class="pi">:</span>
<span class="na">post</span><span class="pi">:</span>
<span class="na">operationId</span><span class="pi">:</span> <span class="s">addBooking</span>
<span class="na">requestBody</span><span class="pi">:</span>
<span class="na">content</span><span class="pi">:</span>
<span class="s">application/json</span><span class="pi">:</span>
<span class="na">schema</span><span class="pi">:</span>
<span class="s">$ref</span><span class="pi">:</span> <span class="s1">'</span><span class="s">#/components/schemas/Booking'</span>
<span class="na">responses</span><span class="pi">:</span>
<span class="s2">"</span><span class="s">200"</span><span class="pi">:</span>
<span class="na">description</span><span class="pi">:</span> <span class="s">OK</span>
</code></pre></div></div>
<p>The Citrus test action now leverages information given in the specification such as resource path <code class="highlighter-rouge">/api/bookings</code> and the content type <code class="highlighter-rouge">application/json</code>.</p>
<h1 id="stage-8-ui-testing-with-selenium">Stage #8: UI testing with Selenium</h1>
<p>Citrus also integrates with Selenium UI testing.
This means that the test is able to open the browser and navigate to the Quarkus application home URL.
Then the test may simulate user interactions such as clicking on links and buttons on the page.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">private</span> <span class="kt">void</span> <span class="nf">approveBooking</span><span class="o">()</span> <span class="o">{</span>
<span class="n">t</span><span class="o">.</span><span class="na">given</span><span class="o">(</span><span class="n">selenium</span><span class="o">()</span>
<span class="o">.</span><span class="na">browser</span><span class="o">(</span><span class="n">browser</span><span class="o">)</span>
<span class="o">.</span><span class="na">start</span><span class="o">());</span>
<span class="n">t</span><span class="o">.</span><span class="na">given</span><span class="o">(</span><span class="n">doFinally</span><span class="o">().</span><span class="na">actions</span><span class="o">(</span>
<span class="n">selenium</span><span class="o">()</span>
<span class="o">.</span><span class="na">browser</span><span class="o">(</span><span class="n">browser</span><span class="o">)</span>
<span class="o">.</span><span class="na">stop</span><span class="o">()));</span>
<span class="n">t</span><span class="o">.</span><span class="na">when</span><span class="o">(</span><span class="n">selenium</span><span class="o">()</span>
<span class="o">.</span><span class="na">browser</span><span class="o">(</span><span class="n">browser</span><span class="o">)</span>
<span class="o">.</span><span class="na">navigate</span><span class="o">(</span><span class="s">"http://localhost:8081"</span><span class="o">));</span>
<span class="n">t</span><span class="o">.</span><span class="na">then</span><span class="o">(</span><span class="n">delay</span><span class="o">().</span><span class="na">seconds</span><span class="o">(</span><span class="mi">3</span><span class="o">));</span>
<span class="n">t</span><span class="o">.</span><span class="na">then</span><span class="o">(</span><span class="n">selenium</span><span class="o">()</span>
<span class="o">.</span><span class="na">browser</span><span class="o">(</span><span class="n">browser</span><span class="o">)</span>
<span class="o">.</span><span class="na">click</span><span class="o">()</span>
<span class="o">.</span><span class="na">element</span><span class="o">(</span><span class="s">"id"</span><span class="o">,</span> <span class="s">"${bookingId}"</span><span class="o">));</span>
<span class="o">}</span>
</code></pre></div></div>
<h2 id="summary">Summary</h2>
<p>The sample application has shown how you can integrate Citrus within a Quarkus test.
The Quarkus test is able to use the Citrus capabilities because of the Citrus Quarkus extension that is provided since Citrus 4.0.</p></content><author><name></name></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://0.0.0.0:4000/img/icons/quarkus.png" /></entry><entry><title type="html">Citrus 4.0.0</title><link href="http://0.0.0.0:4000/news/2023/10/25/release-4.0.0/" rel="alternate" type="text/html" title="Citrus 4.0.0" /><published>2023-10-25T00:00:00+02:00</published><updated>2023-10-25T00:00:00+02:00</updated><id>http://0.0.0.0:4000/news/2023/10/25/release-4.0.0</id><content type="html" xml:base="http://0.0.0.0:4000/news/2023/10/25/release-4.0.0/"><p>The community is proud to announce the availability of Citrus 4.0.0!</p>
<h2 id="objectives">Objectives</h2>
<p>Citrus 4.0 is a major release mainly driven by the industry migrating from <code class="highlighter-rouge">javax.*</code> to <code class="highlighter-rouge">jakarta.*</code> APIs. The new version uses Java 17 and aligns with popular Java enterprise libraries such as Spring Boot and Quarkus. Citrus 4 uses updated versions of many dependency libraries (e.g. Spring 6, Apache Camel 4, Cucumber 7, Selenium 4, Jakarta EE and many more). The proper alignment with those libraries and the evolving of Java’s ecosystem in general is a key driver for Citrus 4.</p>
<p>Of course the new major version also addresses many improvements and fixes. That being said we try to keep breaking changes on a low-level in order to provide a smooth migration from former versions. Due to the breaking changes in the many <code class="highlighter-rouge">javax</code> APIs this might not always be possible though. People coming from Citrus 3.x should have a look at the <a href="https://github.com/citrusframework/citrus/wiki/migration-guide:-citrus-3.x-to-4.x">3.x migration guide</a>.</p>
<p>Here are the main objectives we have with Citrus 4.0</p>
<ul>
<li>Java 17</li>
<li>Move to groupId <code class="highlighter-rouge">org.citrusframework</code></li>
<li>Update dependencies to latest major versions</li>
<li>Move from <code class="highlighter-rouge">javax.*</code> to <code class="highlighter-rouge">jakarta.*</code></li>
<li>Polyglot test runner support (XML, Groovy and YAML)</li>
<li>QuarkusTest runtime support</li>
<li>Remove deprecated modules and code</li>
</ul>
<h2 id="java-17">Java 17</h2>
<p>The Citrus 4.0 bits are compiled with Java 17 (was Java 11 for Citrus 3.x). This means you need to use Java 17 as a minimum to run Citrus.</p>
<p>We recommend to use the following setup:</p>
<ul>
<li>Java 17+</li>
<li>Maven 3.9+</li>
<li>As runtime one of
<ul>
<li>JUnit Jupiter 5.10+</li>
<li>TestNG 7.8+</li>
<li>Cucumber 7.14+</li>
<li>JUnit 4.13+</li>
<li>Quarkus Test 3.4+</li>
</ul>
</li>
</ul>
<p>Of course this also means that you are able to use the full greatness of evolving Java features such as records, multiline text blocks and so many more.</p>
<h2 id="maven-groupid-orgcitrusframework">Maven groupId “org.citrusframework”</h2>
<p>Citrus is an Open Source project and promotes the idea of open code and community contributions. For over a decade Citrus has been using the groupId <code class="highlighter-rouge">com.consol.citrus</code> because the company <a href="https://www.consol.com/">ConSol Software GmbH</a> and its employees have been a driving force in creating and maintaining the project since the very beginning.</p>
<p>Still ConSol plays a significant role in the success of Citrus by adapting and promoting the project in so many ways.
However, the list of new contributors emerges and Citrus benefits from many community contributions these days.</p>
<p>For the sake of strengthening the Open Source idea we decided to move the Citrus groupId from <code class="highlighter-rouge">com.consol.citrus</code> to a more generic <code class="highlighter-rouge">org.citrusframework</code> from Citrus 4.0 onwards.</p>
<p>With the move to <code class="highlighter-rouge">org.citrusframework</code> we decided to happily comply with the Open Source nature of the project because nowadays, the project receives valuable contributions from many companies.</p>
<p>Please update the groupId in your Maven <code class="highlighter-rouge">pom.xml</code> accordingly when updating to Citrus 4.0.</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;dependency&gt;</span>
<span class="nt">&lt;groupId&gt;</span>org.citrusframework<span class="nt">&lt;/groupId&gt;</span>
<span class="nt">&lt;artifactId&gt;</span>citrus-bom<span class="nt">&lt;/artifactId&gt;</span>
<span class="nt">&lt;version&gt;</span>4.5.2<span class="nt">&lt;/version&gt;</span>
<span class="nt">&lt;type&gt;</span>pom<span class="nt">&lt;/type&gt;</span>
<span class="nt">&lt;scope&gt;</span>import<span class="nt">&lt;/scope&gt;</span>
<span class="nt">&lt;/dependency&gt;</span>
</code></pre></div></div>
<p>Since the groupId also represents the basic Java package used in Citrus the packages of all Citrus Java classes have also changed from <code class="highlighter-rouge">com.consol.citrus</code> to <code class="highlighter-rouge">org.citrusframework</code> so please replace all occurrences and imports accordingly as you update.</p>
<p>Please do not worry as it should be nothing more than a search-and-replace operation in your project codebase in order to use the new base package wherever it may be referenced.</p>
<h2 id="dependency-update">Dependency update</h2>
<p>Citrus depends on many fantastic libraries and projects. With the move to the Jakarta API many of them hava had major version releases in 2023. Citrus now aligns with the latest and greatest versions of these libraries.</p>
<p>The new library versions used in Citrus 4.0 are:</p>
<table>
<thead>
<tr>
<th style="text-align: left">Library</th>
<th style="text-align: left">Version</th>
<th style="text-align: left">Library</th>
<th style="text-align: left">Version</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left">JUnit Jupiter</td>
<td style="text-align: left">5.10.0</td>
<td style="text-align: left">TestNG</td>
<td style="text-align: left">7.8.0</td>
</tr>
<tr>
<td style="text-align: left">Cucumber</td>
<td style="text-align: left">7.14.0</td>
<td style="text-align: left">Quarkus Test</td>
<td style="text-align: left">3.4.2</td>
</tr>
<tr>
<td style="text-align: left">Apache Camel</td>
<td style="text-align: left">4.1.0</td>
<td style="text-align: left">ActiveMQ Artemis</td>
<td style="text-align: left">2.31.0</td>
</tr>
<tr>
<td style="text-align: left">ActiveMQ</td>
<td style="text-align: left">5.18.2</td>
<td style="text-align: left">Jetty</td>
<td style="text-align: left">11.0.17</td>
</tr>
<tr>
<td style="text-align: left">HttpClient</td>
<td style="text-align: left">5.2.1</td>
<td style="text-align: left">Cucumber</td>
<td style="text-align: left">7.14.0</td>
</tr>
<tr>
<td style="text-align: left">Knative Client</td>
<td style="text-align: left">6.9.0</td>
<td style="text-align: left">Kubernetes Client</td>
<td style="text-align: left">6.9.0</td>
</tr>
<tr>
<td style="text-align: left">Netty</td>
<td style="text-align: left">4.1.100.Final</td>
<td style="text-align: left">SLF4J</td>
<td style="text-align: left">2.0.9</td>
</tr>
<tr>
<td style="text-align: left">SnakeYAML</td>
<td style="text-align: left">2.2</td>
<td style="text-align: left">Spring Framework</td>
<td style="text-align: left">6.0.13</td>
</tr>
<tr>
<td style="text-align: left">Spring WS</td>
<td style="text-align: left">4.0.7</td>
<td style="text-align: left">Spring Integration</td>
<td style="text-align: left">6.1.4</td>
</tr>
<tr>
<td style="text-align: left">Testcontainers</td>
<td style="text-align: left">1.19.1</td>
<td style="text-align: left">PostrgeSQL</td>
<td style="text-align: left">42.6.0</td>
</tr>
<tr>
<td style="text-align: left">GreenMail</td>
<td style="text-align: left">2.0.0</td>
<td style="text-align: left">Jakarta JMS API</td>
<td style="text-align: left">3.1.0</td>
</tr>
<tr>
<td style="text-align: left">Jakarta Validation</td>
<td style="text-align: left">3.0.2</td>
<td style="text-align: left">Jakarta Websocket API</td>
<td style="text-align: left">2.1.1</td>
</tr>