Since years I’m using Metadata and Tooling Apex classes to connect with those APIs (based on Andrew Fawcetts work here https://github.com/afawcett/apex-toolingapi). Today I’m encountering a very strange issue in form of an package upload error which I can not understand. The issue seems totally wired and without any logical connection…
In hours of work, I was finally able to drill it down to just 3 easy things, 100% reproducible within minutes:
- ToolingAPI.cls (http://www.elastify.org/ToolingAPI.cls) – set to API v36.0
- ToolingAPITest.cls (http://www.elastify.org/ToolingAPITest.cls) – v36.0, too.
- One empty Lightning Component (details below)
Due to size limits I could not save the post with all the code, so I put the classes on my homepage. These are older versions from around 2013, but still work flawlessly.
With just the two classes:
- you can run tests: they succeed with no problems.
- create a new unmanaged package
- add both classes to the package
- upload the package: no problems, tests succeed again.
Now let’s add a blank component:
- create an new empty lightning component (only
<aura:component ></aura:component>) with developer console.
- add that to the package
- and upload it: all good, it still works, no problem!
Finally we add a controller:
- create an empty(!) JS controller inside the lightning component (consisting just of
- try to upload the package again ==> now the Apex tests are failing with
System.CalloutException: You have uncommitted work pending. Please
commit or rollback before calling out
Class.ToolingAPI.submitRestCall: line 2355, column 1,
Class.ToolingAPI.submitRestCall: line 2317, column 1,
Class.ToolingAPI.submitRestCall: line 2309, column 1,
Class.ToolingAPI.query: line 132, column 1,
Class.ToolingAPITest.testQueryApexClassMember: line 67, column 1
- running the test with Dev Console or at setup: no error!
- deleting just the empty controller, I can upload the package again, the error disappeared!
- API version of the compo seems irrelevant. I’ve tried v36.0 and v41.0, no differece.
I can’t figure what can be wrong here. At this point, I can only think of a very strange salesforce error.
It must be related to callouts in conjunction with the existence of a lightning componets JS controller. Crazy! I have another class wrapping the metadata-api based on https://github.com/financialforcedev/apex-mdapi: with that the same is happening.
Update 2017-10-16 – existing package-members immune
I have older packages which contains lots of lightning compos with controllers already. Those I still can upload together with ToolingAPI with no issues – only new compos added are creating the error. However if you save the existing component they will start to produce that error, too. Luckily I got one disposable component to try this… So now I can’t make any changes to all of my vital lightning components, or I will loose the ability to upload the package. Not nice!
Update (2017-10-18) – possibly related with test.setMock()
I think that it is related to the mockup tests. It looks like the
Test.setMock()is not working (e.g. line 56 of
ToolingAPITest.cls) and during the tests, not the mockup, but the real callout is invoked. And as a result it’s failing.
As a workaround I’m trying to hack some
test.isRunningTest()into the code and trying to return null instead something “meaningful”. Also I have to wipe all
System.assert...()to make this fly. But this hack is total crap, plus messing up the code, plus it will degrade my coverage. Bottom-line: this workaround is not OK, but I have to upload this package with a lot of time-pressure – no matter what.
For a real solution I’m out of ideas. Totally.
Unfortunately I have no premier support and Salesforce will shut my ticket down in the support immediately.
I was able to replicate this issue in two packages, so have raised it with support, and they are currently researching it (they were able to re-create it)
One thing I noticed as a workaround – I had many classes with mock callouts, both Web Service and HTTP. But only some failed – and they both did NOT make use of Start/Stop Test.
So even though they worked fine in regular test runs, once I updated my tests to invoke the code that invokes the callouts like below, I could then upload the package.
Test.StartTest() //Invoke code that makes callout Test.Stop Test()