-
Notifications
You must be signed in to change notification settings - Fork 5.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
IDEA-113632 - Fix Geb Page content not being available #2862
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,21 +2,29 @@ | |
package org.jetbrains.plugins.groovy.geb; | ||
|
||
import com.intellij.psi.*; | ||
import com.intellij.psi.impl.source.PsiImmediateClassType; | ||
import com.intellij.psi.scope.PsiScopeProcessor; | ||
import com.intellij.psi.util.CachedValueProvider.Result; | ||
import com.intellij.psi.util.CachedValuesManager; | ||
import org.jetbrains.annotations.NotNull; | ||
import org.jetbrains.annotations.Nullable; | ||
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.GrModifierFlags; | ||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField; | ||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrLabeledStatement; | ||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariableDeclaration; | ||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; | ||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrCall; | ||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; | ||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrMethodCall; | ||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; | ||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter; | ||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; | ||
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.ClassUtil; | ||
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.GrReferenceExpressionImpl; | ||
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrLightField; | ||
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrLightMethodBuilder; | ||
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; | ||
import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; | ||
|
||
import java.util.Collections; | ||
import java.util.HashMap; | ||
|
@@ -37,12 +45,81 @@ public static boolean contributeMembersInsideTest(PsiScopeProcessor processor, | |
|
||
if (pageClass != null) { | ||
if (!pageClass.processDeclarations(processor, state, null, place)) return false; | ||
contributePageContent(processor, state, place); | ||
} | ||
} | ||
|
||
return true; | ||
} | ||
|
||
private static void contributePageContent(PsiScopeProcessor processor, ResolveState state, PsiElement place) { | ||
if(place instanceof GrReferenceExpressionImpl expr | ||
&& !(expr.getParent() instanceof GrMethodCall)) { | ||
|
||
PsiClassType gebPageType = PsiType.getTypeByName("geb.Page", place.getProject(), place.getResolveScope()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We already have |
||
PsiClass ourPage = findPageChange(expr, gebPageType); | ||
if (ourPage != null) { | ||
Map<String, PsiClass> supers = ClassUtil.getSuperClassesWithCache(ourPage); | ||
String nameHint = ResolveUtil.getNameHint(processor); | ||
|
||
for (PsiClass psiClass : supers.values()) { | ||
Map<String, PsiMember> contentElements = getContentElements(psiClass); | ||
|
||
if (nameHint == null) { | ||
for (Map.Entry<String, PsiMember> entry : contentElements.entrySet()) { | ||
processor.execute(entry.getValue(), state); | ||
} | ||
return; | ||
} | ||
else { | ||
PsiVariable defElement = (PsiVariable)contentElements.get(nameHint); | ||
if (defElement != null) { | ||
processor.execute(defElement, state); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
|
||
private static @Nullable PsiClass findPageChange(PsiElement place, PsiClassType pageType) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please, add |
||
PsiElement currentElement = place; | ||
PsiClass ourPage = null; | ||
while (currentElement != null) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems that this method will be invoked for each reference inside the method, but you actually traverse the whole method starting from the innermost block to the outermost. Could you, please, rewrite it in the way like:
|
||
PsiElement examineThis = currentElement; | ||
Comment on lines
+88
to
+90
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please, rename |
||
if (currentElement instanceof GrLabeledStatement labeled) { | ||
examineThis = labeled.getStatement(); | ||
} | ||
if(examineThis instanceof GrVariableDeclaration) { | ||
PsiElement findCall = examineThis.getLastChild(); | ||
while(findCall != null) { | ||
if(findCall instanceof GrExpression) { | ||
examineThis = findCall; | ||
break; | ||
} | ||
findCall = findCall.getLastChild(); | ||
} | ||
} | ||
Comment on lines
+95
to
+103
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry, This construction looks really strange to me. If I understood correctly, you are trying to retrieve the initializer expression of the last variable. To achieve such behaviour, there is more concise approach. You need to retrieve variables by |
||
if (examineThis instanceof GrExpression call && !(examineThis instanceof GrReferenceExpression)) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please, replace to |
||
PsiType ret = call.getType(); | ||
if (ret != null && pageType.isAssignableFrom(ret) && ret instanceof PsiImmediateClassType ct) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry, I think that check |
||
ourPage = ct.resolve(); | ||
break; | ||
} | ||
} | ||
currentElement = currentElement.getPrevSibling(); | ||
} | ||
|
||
if (ourPage == null) { | ||
PsiElement parent = place.getParent(); | ||
if (parent != null && !(parent instanceof GrMethod)) | ||
return findPageChange(parent, pageType); | ||
} | ||
|
||
return ourPage; | ||
} | ||
|
||
public static Map<String, PsiMember> getContentElements(@NotNull PsiClass pageOrModuleClass) { | ||
return CachedValuesManager.getCachedValue(pageOrModuleClass, () -> Result.create( | ||
calculateContentElements(pageOrModuleClass), pageOrModuleClass | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,7 +15,7 @@ import static org.jetbrains.plugins.groovy.GroovyProjectDescriptors.LIB_GROOVY_1 | |
class GebTestsTest extends LightJavaCodeInsightFixtureTestCase { | ||
|
||
private static final TestLibrary LIB_GEB = new RepositoryTestLibrary( | ||
'org.codehaus.geb:geb-core:0.7.2', | ||
'org.gebish:geb-core:7.0', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please, use the version of library, when the feature was firstly available, I think it should be |
||
'org.codehaus.geb:geb-junit4:0.7.2', | ||
'org.codehaus.geb:geb-spock:0.7.2', | ||
'org.codehaus.geb:geb-testng:0.7.2' | ||
|
@@ -283,4 +283,158 @@ class A extends geb.Page { | |
} | ||
""") | ||
} | ||
|
||
void testPageContentIsInScope() { | ||
myFixture.enableInspections(GroovyAssignabilityCheckInspection) | ||
|
||
myFixture.configureByText("SomeSpec.groovy", """ | ||
class SomeSpec extends geb.spock.GebSpec { | ||
Comment on lines
+288
to
+291
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please, don't write tests using groovy language, because we have completely removed it from codebase recently |
||
void "test"() { | ||
expect: | ||
to PageOne | ||
geb.navigator.Navigator aNavigator = header | ||
String aString = headerText | ||
Integer <warning descr="Cannot assign 'Navigator' to 'Integer'">notAnInteger</warning> = header | ||
|
||
then: | ||
header | ||
headerText | ||
} | ||
} | ||
|
||
class PageOne extends geb.Page { | ||
static content = { | ||
header { \$("h1") } | ||
headerText { header.text() } | ||
} | ||
} | ||
|
||
""") | ||
|
||
myFixture.checkHighlighting(true, false, true) | ||
TestUtils.checkResolve(myFixture.file) | ||
} | ||
|
||
void testPageContentIsCompletable() { | ||
myFixture.enableInspections(GroovyAssignabilityCheckInspection) | ||
|
||
myFixture.configureByText("SomeSpec.groovy", """ | ||
class SomeSpec extends geb.spock.GebSpec { | ||
void "test"() { | ||
when: | ||
to PageOne | ||
|
||
then: | ||
<caret> | ||
} | ||
} | ||
|
||
class PageOne extends geb.Page { | ||
static content = { | ||
header { \$("h1") } | ||
headerText { header.text() } | ||
} | ||
} | ||
|
||
""") | ||
|
||
TestUtils.checkCompletionType(myFixture, "header", "geb.navigator.Navigator") | ||
TestUtils.checkCompletionType(myFixture, "headerText", "java.lang.String") | ||
} | ||
|
||
void testOnlyCurrentPageContentIsInScope() { | ||
myFixture.enableInspections(GroovyAssignabilityCheckInspection) | ||
|
||
myFixture.configureByText("SomeSpec.groovy", """ | ||
class SomeSpec extends geb.spock.GebSpec { | ||
void "test"() { | ||
when: | ||
to PageOne | ||
|
||
then: | ||
header | ||
|
||
when: | ||
to PageTwo | ||
|
||
then: | ||
pageTwoContent | ||
headerText | ||
} | ||
} | ||
|
||
class PageOne extends geb.Page { | ||
static content = { | ||
header { \$("h1") } | ||
headerText { header.text() } | ||
} | ||
} | ||
|
||
class PageTwo extends geb.Page { | ||
static content = { | ||
pageTwoContent { \$("h1") } | ||
} | ||
} | ||
|
||
""") | ||
|
||
myFixture.checkHighlighting(true, false, true) | ||
TestUtils.checkResolve(myFixture.file, "headerText") | ||
} | ||
|
||
void testChangingCurrentPage() { | ||
myFixture.enableInspections(GroovyAssignabilityCheckInspection) | ||
|
||
myFixture.configureByText("SomeSpec.groovy", """ | ||
class SomeSpec extends geb.spock.GebSpec { | ||
void "to"() { | ||
when: | ||
to PageOne | ||
|
||
then: | ||
header | ||
} | ||
|
||
void "via"() { | ||
when: | ||
via PageOne | ||
|
||
then: | ||
header | ||
} | ||
|
||
void "at"() { | ||
expect: | ||
at PageOne | ||
header | ||
} | ||
|
||
void "explicit"() { | ||
when: | ||
page(PageOne) | ||
|
||
then: | ||
header | ||
} | ||
|
||
void "assignment"() { | ||
when: | ||
geb.Page newPage = to PageOne | ||
|
||
then: | ||
header | ||
} | ||
} | ||
|
||
class PageOne extends geb.Page { | ||
static content = { | ||
header { \$("h1") } | ||
headerText { header.text() } | ||
} | ||
} | ||
""") | ||
|
||
myFixture.checkHighlighting(true, false, true) | ||
TestUtils.checkResolve(myFixture.file) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, why not just
place instanceof GrReferenceExpression
?