@@ -23,6 +23,21 @@ class LiveCodeTest extends TestCase
2323 */
2424 private static $ reportDir = '' ;
2525
26+ /**
27+ * @var string
28+ */
29+ private static $ changeCheckDir = '' ;
30+
31+ /**
32+ * @var array
33+ */
34+ private static $ uiDataComponentInterface = [
35+ 'Magento\Framework\App\ActionInterface ' ,
36+ 'Magento\Framework\View\Element\BlockInterface ' ,
37+ 'Magento\Framework\View\Element\UiComponentInterface ' ,
38+ 'Magento\Framework\View\Element\UiComponent\DataProvider\DataProviderInterface ' ,
39+ ];
40+
2641 /**
2742 * Setup basics for all tests
2843 */
@@ -32,6 +47,8 @@ public static function setUpBeforeClass(): void
3247 if (!is_dir (self ::$ reportDir )) {
3348 mkdir (self ::$ reportDir , 0770 );
3449 }
50+
51+ self ::$ changeCheckDir = BP . '/app/code/Magento ' ;
3552 }
3653
3754 /**
@@ -50,4 +67,104 @@ public function testCodeStyle(): void
5067 "PHP Code Sniffer detected {$ result } violation(s): " . PHP_EOL . $ report
5168 );
5269 }
70+
71+ /**
72+ * Test if there is corresponding GraphQL module change for each magento core modules
73+ *
74+ * @return void
75+ * @throws \Magento\Framework\Exception\LocalizedException
76+ */
77+ public function testModulesRequireGraphQLChange (): void
78+ {
79+ $ modulesRequireGraphQLChange = self ::getModulesRequiringGraphQLChange ();
80+ $ graphQlModules = implode (", " , $ modulesRequireGraphQLChange );
81+ $ this ->assertEmpty (
82+ $ modulesRequireGraphQLChange ,
83+ "The view layer changes have been detected in the " .
84+ str_replace ("GraphQl " , "" , $ graphQlModules ) . " module. " .
85+ "The " . $ graphQlModules ." module is expected to be updated to reflect these changes. "
86+ );
87+ }
88+
89+ /**
90+ * returns a array with the list of graphql modules which require changes
91+ *
92+ * @return array
93+ */
94+ private static function getModulesRequiringGraphQLChange (): array
95+ {
96+ $ whitelistFiles = PHPCodeTest::getWhitelist (
97+ ['php ' , 'graphqls ' ],
98+ '' ,
99+ '' ,
100+ '/_files/whitelist/graphql.txt '
101+ );
102+
103+ $ updatedGraphQlModules = [];
104+ $ requireGraphQLChanges = [];
105+ foreach ($ whitelistFiles as $ whitelistFile ) {
106+ $ moduleName = self ::getModuleName ($ whitelistFile );
107+
108+ if (!$ moduleName ) {
109+ continue ;
110+ }
111+
112+ $ isGraphQlModule = str_ends_with ($ moduleName , 'GraphQl ' );
113+ if (!in_array ($ moduleName , $ updatedGraphQlModules ) && $ isGraphQlModule ) {
114+ $ updatedGraphQlModules [] = $ moduleName ;
115+ continue ;
116+ }
117+
118+ if (!in_array ($ moduleName , $ requireGraphQLChanges ) && self ::isViewLayerClass ($ whitelistFile )) {
119+ $ requireGraphQLChanges [] = $ moduleName . "GraphQl " ;
120+ }
121+ }
122+ return array_diff ($ requireGraphQLChanges , $ updatedGraphQlModules );
123+ }
124+
125+ /**
126+ * Returns the module name of the file from the path
127+ *
128+ * @param string $filePath
129+ * @return string
130+ */
131+ private static function getModuleName (string $ filePath ): string
132+ {
133+ $ fileName = substr ($ filePath , strlen (self ::$ changeCheckDir ));
134+ $ pathParts = explode ('/ ' , $ fileName );
135+
136+ return $ pathParts [1 ] ?? '' ;
137+ }
138+
139+ /**
140+ * Return true if the class implements any of the defined interfaces
141+ *
142+ * @param string $filePath
143+ * @return bool
144+ */
145+ private static function isViewLayerClass (string $ filePath ): bool
146+ {
147+ $ className = self ::getClassNameWithNamespace ($ filePath );
148+ if (!$ className ) {
149+ return false ;
150+ }
151+
152+ $ implementingInterfaces = array_values (class_implements ($ className ));
153+ return !empty (array_intersect ($ implementingInterfaces , self ::$ uiDataComponentInterface ));
154+ }
155+
156+ /**
157+ * Returns the files namespace using regular expression
158+ *
159+ * @param string $filePath
160+ * @return string
161+ */
162+ private static function getClassNameWithNamespace (string $ filePath ): string
163+ {
164+ $ className = str_replace ('.php ' , '' , basename ($ filePath ));
165+ if (preg_match ('#^namespace\s+(.+?);$#sm ' , file_get_contents ($ filePath ), $ m )) {
166+ return ($ m [1 ] && $ className ) ? $ m [1 ] . "\\" . $ className : '' ;
167+ }
168+ return '' ;
169+ }
53170}
0 commit comments