1+ using System . ComponentModel . DataAnnotations ;
2+ using System . Globalization ;
3+ using EPiServer ;
4+ using EPiServer . Commerce . Catalog . ContentTypes ;
5+ using EPiServer . Core ;
6+ using EPiServer . DataAccess ;
7+ using EPiServer . Security ;
8+ using Mediachase . Commerce ;
9+ using Mediachase . Commerce . Catalog ;
10+ using Microsoft . AspNetCore . Hosting ;
11+ using Microsoft . Extensions . DependencyInjection ;
12+ using Optimizely . TestContainers . Commerce . Tests . Models . Commerce ;
13+ using Optimizely . TestContainers . Shared ;
14+
15+ namespace Optimizely . TestContainers . Commerce . Tests ;
16+
17+ /// <summary>
18+ /// Negative/edge case integration tests for Commerce catalog functionality.
19+ /// Tests error handling, validation, and edge cases for Commerce operations.
20+ /// </summary>
21+ [ Collection ( "CommerceCatalogNegativeTests" ) ]
22+ public class CommerceCatalogNegativeTests ( ) : OptimizelyIntegrationTestBase ( includeCommerce : true )
23+ {
24+ /// <summary>
25+ /// Configure web host with Commerce-specific Startup and services.
26+ /// The base class provides CMS, Commerce, and Find configuration automatically.
27+ /// </summary>
28+ protected override void ConfigureWebHostBuilder ( IWebHostBuilder webHostBuilder )
29+ {
30+ // Register the Startup class that configures Commerce services and content types
31+ webHostBuilder . UseStartup < Startup > ( ) ;
32+ }
33+
34+ [ Fact ]
35+ public void Cannot_Load_NonExistent_Product ( )
36+ {
37+ // Arrange
38+ var contentRepository = Services . GetRequiredService < IContentRepository > ( ) ;
39+ var nonExistentReference = new ContentReference ( 99999 ) ;
40+
41+ // Act & Assert
42+ Assert . Throws < ContentNotFoundException > ( ( ) => contentRepository . Get < TestProduct > ( nonExistentReference ) ) ;
43+ }
44+
45+ [ Fact ]
46+ public void TryGet_Returns_False_For_NonExistent_Product ( )
47+ {
48+ // Arrange
49+ var contentRepository = Services . GetRequiredService < IContentRepository > ( ) ;
50+ var nonExistentReference = new ContentReference ( 99999 ) ;
51+
52+ // Act
53+ var result = contentRepository . TryGet < TestProduct > ( nonExistentReference , out var product ) ;
54+
55+ // Assert
56+ Assert . False ( result ) ;
57+ Assert . Null ( product ) ;
58+ }
59+
60+ [ Fact ]
61+ public void Cannot_Save_Catalog_Without_Name ( )
62+ {
63+ // Arrange
64+ var referenceConverter = Services . GetRequiredService < ReferenceConverter > ( ) ;
65+ var contentRepository = Services . GetRequiredService < IContentRepository > ( ) ;
66+
67+ var rootLink = referenceConverter . GetRootLink ( ) ;
68+
69+ var catalog = contentRepository . GetDefault < CatalogContent > ( rootLink ) ;
70+ catalog . Name = "" ; // Empty name
71+ catalog . DefaultCurrency = Currency . USD ;
72+ catalog . DefaultLanguage = "en" ;
73+ catalog . WeightBase = "kgs" ;
74+ catalog . LengthBase = "cm" ;
75+
76+ // Act & Assert
77+ Assert . Throws < ValidationException > ( ( ) => contentRepository . Save ( catalog , SaveAction . Publish , AccessLevel . NoAccess ) ) ;
78+ }
79+
80+ [ Fact ]
81+ public void Can_Delete_Product ( )
82+ {
83+ // Arrange
84+ var referenceConverter = Services . GetRequiredService < ReferenceConverter > ( ) ;
85+ var contentRepository = Services . GetRequiredService < IContentRepository > ( ) ;
86+
87+ var rootLink = referenceConverter . GetRootLink ( ) ;
88+
89+ var catalog = contentRepository . GetDefault < CatalogContent > ( rootLink ) ;
90+ catalog . Name = "Delete Test Catalog" ;
91+ catalog . DefaultCurrency = Currency . USD ;
92+ catalog . DefaultLanguage = "en" ;
93+ catalog . WeightBase = "kgs" ;
94+ catalog . LengthBase = "cm" ;
95+
96+ var catalogReference = contentRepository . Save ( catalog , SaveAction . Publish , AccessLevel . NoAccess ) ;
97+
98+ var node = contentRepository . GetDefault < NodeContent > ( catalogReference , CultureInfo . GetCultureInfo ( "en" ) ) ;
99+ node . Name = "Delete Test Node" ;
100+ var nodeReference = contentRepository . Save ( node , SaveAction . Publish , AccessLevel . NoAccess ) ;
101+
102+ var product = contentRepository . GetDefault < TestProduct > ( nodeReference , CultureInfo . GetCultureInfo ( "en" ) ) ;
103+ product . Name = "To Be Deleted" ;
104+ product . Description = new XhtmlString ( "<p>Test</p>" ) ;
105+ var productReference = contentRepository . Save ( product , SaveAction . Publish , AccessLevel . NoAccess ) ;
106+
107+ // Act (Delete)
108+ contentRepository . Delete ( productReference , true , AccessLevel . NoAccess ) ;
109+
110+ // Assert
111+ var result = contentRepository . TryGet < TestProduct > ( productReference , out var deleted ) ;
112+ Assert . False ( result ) ;
113+ }
114+
115+ [ Fact ]
116+ public void Can_Update_Existing_Product ( )
117+ {
118+ // Arrange
119+ var referenceConverter = Services . GetRequiredService < ReferenceConverter > ( ) ;
120+ var contentRepository = Services . GetRequiredService < IContentRepository > ( ) ;
121+
122+ var rootLink = referenceConverter . GetRootLink ( ) ;
123+
124+ var catalog = contentRepository . GetDefault < CatalogContent > ( rootLink ) ;
125+ catalog . Name = "Update Test Catalog" ;
126+ catalog . DefaultCurrency = Currency . USD ;
127+ catalog . DefaultLanguage = "en" ;
128+ catalog . WeightBase = "kgs" ;
129+ catalog . LengthBase = "cm" ;
130+
131+ var catalogReference = contentRepository . Save ( catalog , SaveAction . Publish , AccessLevel . NoAccess ) ;
132+
133+ var node = contentRepository . GetDefault < NodeContent > ( catalogReference , CultureInfo . GetCultureInfo ( "en" ) ) ;
134+ node . Name = "Update Test Node" ;
135+ var nodeReference = contentRepository . Save ( node , SaveAction . Publish , AccessLevel . NoAccess ) ;
136+
137+ var product = contentRepository . GetDefault < TestProduct > ( nodeReference , CultureInfo . GetCultureInfo ( "en" ) ) ;
138+ product . Name = "Original Product Name" ;
139+ product . Description = new XhtmlString ( "<p>Original Description</p>" ) ;
140+ var productReference = contentRepository . Save ( product , SaveAction . Publish , AccessLevel . NoAccess ) ;
141+
142+ // Act (Update)
143+ var writable = contentRepository . Get < TestProduct > ( productReference ) . CreateWritableClone ( ) as TestProduct ;
144+ writable ! . Description = new XhtmlString ( "<p>Updated Description</p>" ) ;
145+ contentRepository . Save ( writable , SaveAction . Publish , AccessLevel . NoAccess ) ;
146+
147+ // Assert
148+ var loaded = contentRepository . Get < TestProduct > ( productReference ) ;
149+ Assert . Equal ( "<p>Updated Description</p>" , loaded . Description ? . ToHtmlString ( ) ) ;
150+ }
151+
152+ [ Fact ]
153+ public void Can_Create_Product_As_Draft ( )
154+ {
155+ // Arrange
156+ var referenceConverter = Services . GetRequiredService < ReferenceConverter > ( ) ;
157+ var contentRepository = Services . GetRequiredService < IContentRepository > ( ) ;
158+
159+ var rootLink = referenceConverter . GetRootLink ( ) ;
160+
161+ var catalog = contentRepository . GetDefault < CatalogContent > ( rootLink ) ;
162+ catalog . Name = "Draft Test Catalog" ;
163+ catalog . DefaultCurrency = Currency . USD ;
164+ catalog . DefaultLanguage = "en" ;
165+ catalog . WeightBase = "kgs" ;
166+ catalog . LengthBase = "cm" ;
167+
168+ var catalogReference = contentRepository . Save ( catalog , SaveAction . Publish , AccessLevel . NoAccess ) ;
169+
170+ var node = contentRepository . GetDefault < NodeContent > ( catalogReference , CultureInfo . GetCultureInfo ( "en" ) ) ;
171+ node . Name = "Draft Test Node" ;
172+ var nodeReference = contentRepository . Save ( node , SaveAction . Publish , AccessLevel . NoAccess ) ;
173+
174+ var product = contentRepository . GetDefault < TestProduct > ( nodeReference , CultureInfo . GetCultureInfo ( "en" ) ) ;
175+ product . Name = "Draft Product" ;
176+ product . Description = new XhtmlString ( "<p>Draft Description</p>" ) ;
177+
178+ // Act (Save as draft)
179+ var productReference = contentRepository . Save ( product , SaveAction . CheckOut , AccessLevel . NoAccess ) ;
180+ var loaded = contentRepository . Get < TestProduct > ( productReference ) ;
181+
182+ // Assert
183+ Assert . NotNull ( loaded ) ;
184+ Assert . Equal ( "Draft Product" , loaded . Name ) ;
185+ Assert . False ( loaded . Status == VersionStatus . Published ) ;
186+ }
187+
188+ [ Fact ]
189+ public void Cannot_Get_Wrong_Content_Type_From_Catalog ( )
190+ {
191+ // Arrange
192+ var referenceConverter = Services . GetRequiredService < ReferenceConverter > ( ) ;
193+ var contentRepository = Services . GetRequiredService < IContentRepository > ( ) ;
194+
195+ var rootLink = referenceConverter . GetRootLink ( ) ;
196+
197+ var catalog = contentRepository . GetDefault < CatalogContent > ( rootLink ) ;
198+ catalog . Name = "Type Test Catalog" ;
199+ catalog . DefaultCurrency = Currency . USD ;
200+ catalog . DefaultLanguage = "en" ;
201+ catalog . WeightBase = "kgs" ;
202+ catalog . LengthBase = "cm" ;
203+
204+ var catalogReference = contentRepository . Save ( catalog , SaveAction . Publish , AccessLevel . NoAccess ) ;
205+
206+ // Act & Assert - Try to get Catalog as Product
207+ Assert . Throws < TypeMismatchException > ( ( ) => contentRepository . Get < TestProduct > ( catalogReference ) ) ;
208+ }
209+
210+ [ Fact ]
211+ public void Can_Create_Multiple_Products_In_Same_Node ( )
212+ {
213+ // Arrange
214+ var referenceConverter = Services . GetRequiredService < ReferenceConverter > ( ) ;
215+ var contentRepository = Services . GetRequiredService < IContentRepository > ( ) ;
216+
217+ var rootLink = referenceConverter . GetRootLink ( ) ;
218+
219+ var catalog = contentRepository . GetDefault < CatalogContent > ( rootLink ) ;
220+ catalog . Name = "Multiple Products Catalog" ;
221+ catalog . DefaultCurrency = Currency . USD ;
222+ catalog . DefaultLanguage = "en" ;
223+ catalog . WeightBase = "kgs" ;
224+ catalog . LengthBase = "cm" ;
225+
226+ var catalogReference = contentRepository . Save ( catalog , SaveAction . Publish , AccessLevel . NoAccess ) ;
227+
228+ var node = contentRepository . GetDefault < NodeContent > ( catalogReference , CultureInfo . GetCultureInfo ( "en" ) ) ;
229+ node . Name = "Multiple Products Node" ;
230+ var nodeReference = contentRepository . Save ( node , SaveAction . Publish , AccessLevel . NoAccess ) ;
231+
232+ // Create first product
233+ var product1 = contentRepository . GetDefault < TestProduct > ( nodeReference , CultureInfo . GetCultureInfo ( "en" ) ) ;
234+ product1 . Name = "Product 1" ;
235+ product1 . Description = new XhtmlString ( "<p>Description 1</p>" ) ;
236+ var productRef1 = contentRepository . Save ( product1 , SaveAction . Publish , AccessLevel . NoAccess ) ;
237+
238+ // Create second product
239+ var product2 = contentRepository . GetDefault < TestProduct > ( nodeReference , CultureInfo . GetCultureInfo ( "en" ) ) ;
240+ product2 . Name = "Product 2" ;
241+ product2 . Description = new XhtmlString ( "<p>Description 2</p>" ) ;
242+
243+ // Act
244+ var productRef2 = contentRepository . Save ( product2 , SaveAction . Publish , AccessLevel . NoAccess ) ;
245+
246+ // Assert
247+ var loaded1 = contentRepository . Get < TestProduct > ( productRef1 ) ;
248+ var loaded2 = contentRepository . Get < TestProduct > ( productRef2 ) ;
249+
250+ Assert . NotNull ( loaded1 ) ;
251+ Assert . NotNull ( loaded2 ) ;
252+ Assert . Equal ( "Product 1" , loaded1 . Name ) ;
253+ Assert . Equal ( "Product 2" , loaded2 . Name ) ;
254+ Assert . NotEqual ( loaded1 . ContentLink , loaded2 . ContentLink ) ;
255+ }
256+ }
0 commit comments