Skip to content

Commit 0c2eeb2

Browse files
committed
feat: implement copy command tests and update VendorFileMapper
1 parent 3847442 commit 0c2eeb2

5 files changed

Lines changed: 701 additions & 7 deletions

File tree

.github/workflows/magento-compatibility.yml

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,45 @@ jobs:
147147
bin/magento hyva:check --help
148148
bin/magento hyva:tokens --help
149149
150+
- name: Test Copy Command Functionality
151+
working-directory: magento2
152+
run: |
153+
echo "Test: Copy frontend file to frontend theme (dry-run):"
154+
bin/magento mageforge:theme:copy-from-vendor \
155+
vendor/magento/module-catalog/view/frontend/templates/product/list.phtml \
156+
Magento/luma \
157+
--dry-run
158+
159+
echo "Test: Copy base file to frontend theme (dry-run):"
160+
bin/magento mageforge:theme:copy-from-vendor \
161+
vendor/magento/module-theme/view/base/web/css/print.css \
162+
Magento/blank \
163+
--dry-run
164+
165+
echo "Test: Verify non-view file is rejected:"
166+
if bin/magento mageforge:theme:copy-from-vendor \
167+
vendor/magento/module-catalog/etc/di.xml \
168+
Magento/luma \
169+
--dry-run 2>&1 | grep -q "not under a view"; then
170+
echo "✓ Non-view file correctly rejected"
171+
else
172+
echo "✗ Non-view file validation failed"
173+
exit 1
174+
fi
175+
176+
echo "Test: Verify cross-area mapping is rejected (frontend -> adminhtml):"
177+
if bin/magento mageforge:theme:copy-from-vendor \
178+
vendor/magento/module-catalog/view/frontend/templates/product/list.phtml \
179+
Magento/backend \
180+
--dry-run 2>&1 | grep -q "Cannot map file from area"; then
181+
echo "✓ Cross-area mapping correctly rejected"
182+
else
183+
echo "✗ Cross-area validation failed"
184+
exit 1
185+
fi
186+
187+
echo "All copy command tests passed!"
188+
150189
- name: Test Summary
151190
run: |
152191
echo "MageForge module compatibility test with Magento ${{ matrix.magento-version }} completed"
@@ -280,6 +319,45 @@ jobs:
280319
bin/magento hyva:check --help
281320
bin/magento hyva:tokens --help
282321
322+
- name: Test Copy Command Functionality
323+
working-directory: magento2
324+
run: |
325+
echo "Test: Copy frontend file to frontend theme (dry-run):"
326+
bin/magento mageforge:theme:copy-from-vendor \
327+
vendor/magento/module-catalog/view/frontend/templates/product/list.phtml \
328+
Magento/luma \
329+
--dry-run
330+
331+
echo "Test: Copy base file to frontend theme (dry-run):"
332+
bin/magento mageforge:theme:copy-from-vendor \
333+
vendor/magento/module-theme/view/base/web/css/print.css \
334+
Magento/blank \
335+
--dry-run
336+
337+
echo "Test: Verify non-view file is rejected:"
338+
if bin/magento mageforge:theme:copy-from-vendor \
339+
vendor/magento/module-catalog/etc/di.xml \
340+
Magento/luma \
341+
--dry-run 2>&1 | grep -q "not under a view"; then
342+
echo "✓ Non-view file correctly rejected"
343+
else
344+
echo "✗ Non-view file validation failed"
345+
exit 1
346+
fi
347+
348+
echo "Test: Verify cross-area mapping is rejected (frontend -> adminhtml):"
349+
if bin/magento mageforge:theme:copy-from-vendor \
350+
vendor/magento/module-catalog/view/frontend/templates/product/list.phtml \
351+
Magento/backend \
352+
--dry-run 2>&1 | grep -q "Cannot map file from area"; then
353+
echo "✓ Cross-area mapping correctly rejected"
354+
else
355+
echo "✗ Cross-area validation failed"
356+
exit 1
357+
fi
358+
359+
echo "All copy command tests passed!"
360+
283361
- name: Test Summary
284362
run: |
285363
echo "MageForge module compatibility test with Magento 2.4.8 completed"
Lines changed: 299 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,299 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace OpenForgeProject\MageForge\Test\Unit\Service;
6+
7+
use Magento\Framework\Component\ComponentRegistrar;
8+
use Magento\Framework\Component\ComponentRegistrarInterface;
9+
use Magento\Framework\Filesystem\DirectoryList;
10+
use OpenForgeProject\MageForge\Service\VendorFileMapper;
11+
use PHPUnit\Framework\TestCase;
12+
use PHPUnit\Framework\MockObject\MockObject;
13+
use RuntimeException;
14+
15+
/**
16+
* Test VendorFileMapper service
17+
*
18+
* Note: Most tests pass theme area explicitly to mapToThemePath().
19+
* The method can also extract area from theme path, but explicit passing
20+
* is recommended for clarity and when theme path doesn't contain area info.
21+
*/
22+
class VendorFileMapperTest extends TestCase
23+
{
24+
private VendorFileMapper $vendorFileMapper;
25+
private ComponentRegistrarInterface|MockObject $componentRegistrar;
26+
private DirectoryList|MockObject $directoryList;
27+
28+
protected function setUp(): void
29+
{
30+
$this->componentRegistrar = $this->createMock(ComponentRegistrarInterface::class);
31+
$this->directoryList = $this->createMock(DirectoryList::class);
32+
$this->directoryList->method('getRoot')->willReturn('/var/www/html/magento');
33+
34+
$this->vendorFileMapper = new VendorFileMapper(
35+
$this->componentRegistrar,
36+
$this->directoryList
37+
);
38+
}
39+
40+
/**
41+
* Test mapping from module view/frontend to frontend theme
42+
*/
43+
public function testMapFrontendFileToFrontendTheme(): void
44+
{
45+
$this->componentRegistrar->method('getPaths')
46+
->willReturn([
47+
'Magento_Catalog' => '/var/www/html/magento/vendor/magento/module-catalog'
48+
]);
49+
50+
$sourcePath = 'vendor/magento/module-catalog/view/frontend/templates/product/list.phtml';
51+
$themePath = '/var/www/html/magento/app/design/frontend/Magento/luma';
52+
$themeArea = 'frontend';
53+
54+
$result = $this->vendorFileMapper->mapToThemePath($sourcePath, $themePath, $themeArea);
55+
56+
$this->assertEquals(
57+
'/var/www/html/magento/app/design/frontend/Magento/luma/Magento_Catalog/templates/product/list.phtml',
58+
$result
59+
);
60+
}
61+
62+
/**
63+
* Test mapping from module view/base to frontend theme (base is compatible)
64+
*/
65+
public function testMapBaseFileToFrontendTheme(): void
66+
{
67+
$this->componentRegistrar->method('getPaths')
68+
->willReturn([
69+
'Magento_Theme' => '/var/www/html/magento/vendor/magento/module-theme'
70+
]);
71+
72+
$sourcePath = 'vendor/magento/module-theme/view/base/web/css/styles.css';
73+
$themePath = '/var/www/html/magento/app/design/frontend/Magento/luma';
74+
75+
$result = $this->vendorFileMapper->mapToThemePath($sourcePath, $themePath);
76+
77+
$this->assertEquals(
78+
'/var/www/html/magento/app/design/frontend/Magento/luma/Magento_Theme/web/css/styles.css',
79+
$result
80+
);
81+
}
82+
83+
/**
84+
* Test mapping from module view/adminhtml to adminhtml theme
85+
*/
86+
public function testMapAdminhtmlFileToAdminhtmlTheme(): void
87+
{
88+
$this->componentRegistrar->method('getPaths')
89+
->willReturn([
90+
'Magento_Backend' => '/var/www/html/magento/vendor/magento/module-backend'
91+
]);
92+
93+
$sourcePath = 'vendor/magento/module-backend/view/adminhtml/templates/dashboard.phtml';
94+
$themePath = '/var/www/html/magento/app/design/adminhtml/Magento/backend';
95+
96+
$result = $this->vendorFileMapper->mapToThemePath($sourcePath, $themePath);
97+
98+
$this->assertEquals(
99+
'/var/www/html/magento/app/design/adminhtml/Magento/backend/Magento_Backend/templates/dashboard.phtml',
100+
$result
101+
);
102+
}
103+
104+
/**
105+
* Test mapping from module view/base to adminhtml theme (base is compatible)
106+
*/
107+
public function testMapBaseFileToAdminhtmlTheme(): void
108+
{
109+
$this->componentRegistrar->method('getPaths')
110+
->willReturn([
111+
'Magento_Ui' => '/var/www/html/magento/vendor/magento/module-ui'
112+
]);
113+
114+
$sourcePath = 'vendor/magento/module-ui/view/base/web/js/grid/columns/column.js';
115+
$themePath = '/var/www/html/magento/app/design/adminhtml/Magento/backend';
116+
117+
$result = $this->vendorFileMapper->mapToThemePath($sourcePath, $themePath);
118+
119+
$this->assertEquals(
120+
'/var/www/html/magento/app/design/adminhtml/Magento/backend/Magento_Ui/web/js/grid/columns/column.js',
121+
$result
122+
);
123+
}
124+
125+
/**
126+
* Test that adminhtml files cannot be mapped to frontend themes
127+
*/
128+
public function testAdminhtmlFileToFrontendThemeThrowsException(): void
129+
{
130+
$this->componentRegistrar->method('getPaths')
131+
->willReturn([
132+
'Magento_Backend' => '/var/www/html/magento/vendor/magento/module-backend'
133+
]);
134+
135+
$sourcePath = 'vendor/magento/module-backend/view/adminhtml/templates/dashboard.phtml';
136+
$themePath = '/var/www/html/magento/app/design/frontend/Magento/luma';
137+
138+
$this->expectException(RuntimeException::class);
139+
$this->expectExceptionMessage("Cannot map file from area 'adminhtml' to frontend theme");
140+
141+
$this->vendorFileMapper->mapToThemePath($sourcePath, $themePath);
142+
}
143+
144+
/**
145+
* Test that frontend files cannot be mapped to adminhtml themes
146+
*/
147+
public function testFrontendFileToAdminhtmlThemeThrowsException(): void
148+
{
149+
$this->componentRegistrar->method('getPaths')
150+
->willReturn([
151+
'Magento_Catalog' => '/var/www/html/magento/vendor/magento/module-catalog'
152+
]);
153+
154+
$sourcePath = 'vendor/magento/module-catalog/view/frontend/templates/product/list.phtml';
155+
$themePath = '/var/www/html/magento/app/design/adminhtml/Magento/backend';
156+
157+
$this->expectException(RuntimeException::class);
158+
$this->expectExceptionMessage("Cannot map file from area 'frontend' to adminhtml theme");
159+
160+
$this->vendorFileMapper->mapToThemePath($sourcePath, $themePath);
161+
}
162+
163+
/**
164+
* Test that files outside view/ directory throw exception
165+
*/
166+
public function testNonViewFileThrowsException(): void
167+
{
168+
$this->componentRegistrar->method('getPaths')
169+
->willReturn([
170+
'Magento_Catalog' => '/var/www/html/magento/vendor/magento/module-catalog'
171+
]);
172+
173+
$sourcePath = 'vendor/magento/module-catalog/etc/di.xml';
174+
$themePath = '/var/www/html/magento/app/design/frontend/Magento/luma';
175+
176+
$this->expectException(RuntimeException::class);
177+
$this->expectExceptionMessage("File is not under a view/ directory");
178+
179+
$this->vendorFileMapper->mapToThemePath($sourcePath, $themePath);
180+
}
181+
182+
/**
183+
* Test nested module pattern (e.g., from Hyva compatibility modules)
184+
*/
185+
public function testNestedModulePattern(): void
186+
{
187+
$this->componentRegistrar->method('getPaths')
188+
->willReturn([]);
189+
190+
$sourcePath = 'vendor/hyva-themes/magento2-hyva-checkout/src/view/frontend/Magento_Checkout/templates/cart.phtml';
191+
$themePath = '/var/www/html/magento/app/design/frontend/Hyva/default';
192+
193+
$result = $this->vendorFileMapper->mapToThemePath($sourcePath, $themePath);
194+
195+
$this->assertEquals(
196+
'/var/www/html/magento/app/design/frontend/Hyva/default/Magento_Checkout/templates/cart.phtml',
197+
$result
198+
);
199+
}
200+
201+
/**
202+
* Test nested module pattern with area validation
203+
*/
204+
public function testNestedModulePatternWithWrongArea(): void
205+
{
206+
$this->componentRegistrar->method('getPaths')
207+
->willReturn([]);
208+
209+
$sourcePath = 'vendor/some-vendor/module/src/view/adminhtml/Magento_Backend/templates/test.phtml';
210+
$themePath = '/var/www/html/magento/app/design/frontend/Magento/luma';
211+
212+
$this->expectException(RuntimeException::class);
213+
$this->expectExceptionMessage("Cannot map file from area 'adminhtml' to frontend theme");
214+
215+
$this->vendorFileMapper->mapToThemePath($sourcePath, $themePath);
216+
}
217+
218+
/**
219+
* Test absolute path normalization
220+
*/
221+
public function testAbsolutePathNormalization(): void
222+
{
223+
$this->componentRegistrar->method('getPaths')
224+
->willReturn([
225+
'Magento_Catalog' => '/var/www/html/magento/vendor/magento/module-catalog'
226+
]);
227+
228+
$sourcePath = '/var/www/html/magento/vendor/magento/module-catalog/view/frontend/templates/product/list.phtml';
229+
$themePath = '/var/www/html/magento/app/design/frontend/Magento/luma';
230+
231+
$result = $this->vendorFileMapper->mapToThemePath($sourcePath, $themePath);
232+
233+
$this->assertEquals(
234+
'/var/www/html/magento/app/design/frontend/Magento/luma/Magento_Catalog/templates/product/list.phtml',
235+
$result
236+
);
237+
}
238+
239+
/**
240+
* Test Hyvä theme with base file
241+
*/
242+
public function testHyvaThemeWithBaseFile(): void
243+
{
244+
$this->componentRegistrar->method('getPaths')
245+
->willReturn([
246+
'Hyva_Theme' => '/var/www/html/magento/vendor/hyva-themes/magento2-default-theme'
247+
]);
248+
249+
$sourcePath = 'vendor/hyva-themes/magento2-default-theme/view/base/web/tailwind/tailwind.css';
250+
$themePath = '/var/www/html/magento/app/design/frontend/Hyva/default';
251+
252+
$result = $this->vendorFileMapper->mapToThemePath($sourcePath, $themePath);
253+
254+
$this->assertEquals(
255+
'/var/www/html/magento/app/design/frontend/Hyva/default/Hyva_Theme/web/tailwind/tailwind.css',
256+
$result
257+
);
258+
}
259+
260+
/**
261+
* Test custom theme (Tailwind-based without Hyvä)
262+
*/
263+
public function testCustomTailwindTheme(): void
264+
{
265+
$this->componentRegistrar->method('getPaths')
266+
->willReturn([
267+
'Magento_Theme' => '/var/www/html/magento/vendor/magento/module-theme'
268+
]);
269+
270+
$sourcePath = 'vendor/magento/module-theme/view/frontend/layout/default.xml';
271+
$themePath = '/var/www/html/magento/app/design/frontend/Custom/tailwind';
272+
273+
$result = $this->vendorFileMapper->mapToThemePath($sourcePath, $themePath);
274+
275+
$this->assertEquals(
276+
'/var/www/html/magento/app/design/frontend/Custom/tailwind/Magento_Theme/layout/default.xml',
277+
$result
278+
);
279+
}
280+
281+
/**
282+
* Test that theme path without area throws exception
283+
*/
284+
public function testThemePathWithoutAreaThrowsException(): void
285+
{
286+
$this->componentRegistrar->method('getPaths')
287+
->willReturn([
288+
'Magento_Catalog' => '/var/www/html/magento/vendor/magento/module-catalog'
289+
]);
290+
291+
$sourcePath = 'vendor/magento/module-catalog/view/frontend/templates/test.phtml';
292+
$themePath = '/var/www/html/magento/app/design/Magento/luma'; // Missing frontend/adminhtml
293+
294+
$this->expectException(RuntimeException::class);
295+
$this->expectExceptionMessage("Could not determine theme area from path");
296+
297+
$this->vendorFileMapper->mapToThemePath($sourcePath, $themePath);
298+
}
299+
}

0 commit comments

Comments
 (0)